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

Posted

技术标签:

【中文标题】具有相同值的 NSManagedObjects 的 CoreData NSSet-Like 行为【英文标题】:CoreData NSSet-Like behavior for NSManagedObjects with the same values 【发布时间】:2016-07-26 12:08:40 【问题描述】:

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

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

我现在的问题:有时,如果我从备份中收到旧消息,我的 DataModel 中有两次消息。我想要一个类似 NSSet 的类,它可以识别 Message-Object 的属性是否具有完全相同的值。我读过,我不能重写方法-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;

【问题讨论】:

【参考方案1】:

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

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

你的哈希方法可能看起来像这样:

- (NSUInteger)hash 

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

这不是哈希函数的最佳实现。看看这个答案:https://***.com/a/5915445/2696922

对于 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;
    

【讨论】:

谢谢!你确定我可以毫无问题地覆盖散列函数吗? 如果我覆盖 isEqual,我的应用程序将崩溃。实体“消息”的“消息”类非法覆盖 NSManagedObject -isEqual: 很抱歉我说你可以覆盖哈希和 isEqual 是错误的。但是,您可以做的是创建另一个具有不同名称的方法并将您的 isEqual 逻辑移到那里。您可以忽略哈希方法,因为您只想检查两个对象是否具有相同的数据。看看这是否有效。【参考方案2】:

我现在做的是手动检查,如果我的 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;
  

【讨论】:

以上是关于具有相同值的 NSManagedObjects 的 CoreData NSSet-Like 行为的主要内容,如果未能解决你的问题,请参考以下文章

使用java在sql中查找具有相同数据的具有相同值的行?

聚合具有两个或多个具有相同值的列的行

计算具有相同 id 的列的值的存储过程

mysql返回最大n个具有相同值的行

R - 删除具有相同值的行和具有相同值组合的行

将值放入具有相同值的数组中