1

I have a Chat-App with a Data-Modell like this.

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

My Problem now: Sometimes, if I get old messages from a Backup, I have Messages twice in my DataModel. I'd like to have a NSSet-Like Class which recognizes, if a Message-Object has exactly the same values on it's properties. I've read, that I must not override the methods -hash and -isEqual:, so I don't know how to do it. Any Idea? Here is some code...

+(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
}
}

And the Conversation -addMessages: Method is the one automatically generated from Xcode/CoreData

- (void)addMessages:(NSSet<Message *> *)values;
Stephan Boner
  • 733
  • 1
  • 6
  • 27

2 Answers2

0

One way of doing it would be to add unique constraints on your entity for one or more attributes. But, this feature was added from iOS 9. Here's the link to the WWDC video explaining it: https://developer.apple.com/videos/play/wwdc2015/220/

As a final option, you can always override hash and equal, if that suits your logic and requirements.

You hash method could look something like this:

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

This is not the best implementation of a hash function. Check out this answer: https://stackoverflow.com/a/5915445/2696922

For the isEqual method, it could look something like:

- (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;
    }
}
Community
  • 1
  • 1
  • thank you! Are you sure I can override the hash function without any trouble? – Stephan Boner Jul 27 '16 at 07:36
  • If I override isEqual, my app will crash.. **Class 'Message' for entity 'Message' has an illegal override of NSManagedObject -isEqual:** – Stephan Boner Jul 27 '16 at 07:53
  • I am sorry I was wrong in saying that you can override hash and isEqual. What you can do though is create another method with a different name and move your isEqual logic there. You can ignore hash method since you just want to be able to check if two objects have same data or not. See if that works. – Kunal Shrivastava Jul 27 '16 at 09:45
0

What I do now is checking manually, if there is a Object with same Attributes in my MOC. If there is one, I skip the creation. I know, it is a bit inefficient but with my expected number of messages, this should be no problem.

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;
  }
Stephan Boner
  • 733
  • 1
  • 6
  • 27