具有相同值的 NSManagedObjects 的 CoreData NSSet-Like 行为

CoreData NSSet-Like behavior for NSManagedObjects with the same values

我有一个带有这样数据模型的聊天应用程序。

User <--> Conversation <-->> Message

我现在的问题:有时,如果我从备份中获取旧消息,我的数据模型中会有两次消息。我想要一个 NSSet-Like Class 来识别消息对象是否在其属性上具有完全相同的值。我读过,我不能覆盖方法 -hash-isEqual:,所以我不知道该怎么做。任何的想法?这是一些代码...

+(void)addMessages:(NSSet<JSQMessage *> *)messages toConversation:(Conversation *)conversation
{
    DataManager * dataManager = [DataManager dataManager];
    NSMutableSet * storeSet = [NSMutableSet setWithCapacity:messages.count];

for (JSQMessage * jsqMessage in messages) {
    Message * message = [NSEntityDescription insertNewObjectForEntityForName:CDEntityNameMessage inManagedObjectContext:[dataManager managedObjectContext]];
    message.senderId = jsqMessage.senderId;
    message.senderDisplayName = jsqMessage.senderDisplayName;
    message.text = jsqMessage.text;
    message.date = jsqMessage.date;
    [storeSet addObject:message];
}
[conversation addMessages:storeSet];

NSError *error;
if (![[dataManager managedObjectContext] save:&error]) {
    NSLog(@"Something went wrong: %@", [error localizedDescription]);
} else {
    //Saved successfull
}
}

Conversation -addMessages: 方法是从 Xcode/CoreData

自动生成的方法
- (void)addMessages:(NSSet<Message *> *)values;

一种方法是为您的实体添加一个或多个属性的唯一约束。但是,此功能是从 iOS 9 添加的。这是解释它的 WWDC 视频的 link: https://developer.apple.com/videos/play/wwdc2015/220/

作为最后一个选项,如果符合您的逻辑和要求,您始终可以覆盖散列和等于。

您的哈希方法可能如下所示:

- (NSUInteger)hash 
{
    NSInteger hashResult = 0;
    for (NSObject *ob in self)
    {
        hashResult ^= [ob hash];
    }
}

这不是散列函数的最佳实现。查看此答案:

对于 isEqual 方法,它可能类似于:

- (BOOL)isEqual:(id)object 
{
    if (self == object) 
    {
        return YES;
    }

    if (object == nil || ![object isKindOfClass:[JSQMessage class]]) 
    {
        return NO;
    }

    JSQMessage *jsqMessage = (JSQMessage*)object;

    //You can have more parameters here based on your business logic
    if (self.message != jsqMessage.message && self.date != jsqMessage.date)
    {
        return NO;
    }
}

我现在做的是手动检查我的 MOC 中是否有具有相同属性的对象。如果有的话,我会跳过创建。我知道,这有点低效,但按照我预期的消息数量,这应该没问题。

NSFetchRequest * fr = [NSFetchRequest fetchRequestWithEntityName:CDEntityNameMessage];
  [fr setPredicate:[NSPredicate predicateWithFormat:@"text == %@ AND date == %@ AND conversation.user.objectId == %@", message.text, message.date, chatpartner.objectId]];
  NSArray * results = [[self managedObjectContext] executeFetchRequest:fr error:nil];
  if (results && results.count > 0) {
     continue;
  }