Design for a chat app using Core Data

前端 未结 2 1393
南笙
南笙 2021-02-02 03:13

I\'m writing a chat app and I\'m in the process of changing my db to use Core Data. I currently use sqlite directly but I want to take advantage of iCloud feature so I\'m switch

相关标签:
2条回答
  • 2021-02-02 03:47

    Having an app that does exactly the same thing, here are my insights.

    First of all you should consider coredata and multithreading wisely before coding. If you need help on that let me know.

    The model

    You are working with entities in Coredata, which can be considered like tables in sqlite, but in a more abstract way. You should review Apple's documentation for that.

    We can find at least three different entities in your case : User, Conversation, and Message. (be careful with the last one, I had an issue with the entity called Message when importing the SMS Framework, you should consider prefixing the name of the entity..)

    An issue with coredata is that you can not store directly arrays (may be with some unknown type) but anyway. So two solutions to store your users : either in a NSString when they will be delimited by comas and a simple regex or split will give you the number of users..

    so your model could look like :

    Conversation{
         messages<-->>Message.conversation
         lastMessage<-->Message.whateverName
         //optional
         users<<-->>User.conversation
    }
    
    Message{
        conversation<<-->Conversation.messages
        whatevername<-->Conversation.lastmessage // "whatever as it does not really matter"
    }
    
    User{
        conversations<<-->>Conversation.users
    }
    

    Conversation must have an to-many relationship to Message and Message a to-one relationship to Conversation.

    --EDIT

    If you want to display the last message of a conversation just like the message App (or my app), you can add one relationship with message. It won't store the message twice in the database/coredata. Indeed, you create a coredata object (in this case a message) and that you add it to a conversation, what happen inside is that a conversation store the coredata ID for that object. Adding one relationship for this message (lastMessage) will only store another ID, and not another object.

    --end of EDIT

    Users are slightly different because they can be part of multiple conversations (because of the group conversation) that is why you need a many-to-many relation ship.

    You can add as many attributes as you want, but that's the minimal requirement !

    1. Implementation

    then in your code, if you want to mimic the behavior of iMessage, here is what I did :

    in the first controller, where you can see all the conversation : use a NSFetchedResultController. The query should be only about the entity Conversation.

    When clicking on a row, what I did is that the new view has the conversation object and another NSFtechedResultController. I then query only the entity Message but with a predicate specifying that I only want this conversation.

    If you want to check my app to see the fluidity, go to this link.

    EDIT

    1. Code snippet to find the last Message Of A Conversation

    Beware: This is a temporary answer before finding a better way to do it (i.e. when using fetched properties)

    NSFetchRequest * req = [[NSFetchRequest alloc] init];
    [req setEntity:[NSEntityDescription entityForName:@"Message" inManagedObjectContext:context]];
    [req setPredicate:[NSPredicate predicateWithFormat:@"conversation == %@", self]]; /* did that from a Conversation object.. */
    NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:@"sent_date" ascending:NO];
    [req setSortDescriptors:[NSArray arrayWithObject:sort]];
    
    [sort release];
    NSError * error = nil;
    NSArray * messages = [context executeFetchRequest:req error:&error];
    [req release];
    if ([messages count] > 0) { /* sanity check */
        return [messages objectAtIndex:0];
    }
    return nil;
    

    --end of EDIT

    Hope this help !

    Pierre

    0 讨论(0)
  • 2021-02-02 03:52

    First, your mental model is all wrong. You should not think of core data as a SQL database. Yes, most of the time it uses SQL, but it is merely an implementation detail. You should think in terms of object graphs.

    Next, for your "50 items" issue, look at NSFetchRequest. You can tell it where to start (fetchOffset), and how many items to fetch (fetchLimit). There are other options for you as well. If your total number of items is relatively small, you can just fetch the entire array (and only fault so many at a time - see fetchBatchSize).

    For your "join" consider how objects are related to each other, not database table joins. Unfortunately, I do not understand what you are trying to achieve with that part of the question. However, you can mimic "joined" tables by using the dot notation when forming your predicate.

    EDIT

    When you create a conversation object, you can include a to-many relationship to something like "participants" which would be a set of all the users that participated in that conversation. The inverse would also be a to-many relationship in "user" that contained all the conversations that user participated in (I assume your database has multiple users???).

    So, to get all the conversations in which a particular user participated, you could do something like fetch on "Participant" with a predicate similar to "ALL participants.username = %@"

    0 讨论(0)
提交回复
热议问题