使用Core Data设计聊天应用程序 [英] Design for a chat app using Core Data

查看:156
本文介绍了使用Core Data设计聊天应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在写一个聊天应用,我正在改变我的数据库以使用核心数据。我目前直接使用sqlite,但我想利用iCloud功能,所以我切换引擎。



我的主表被称为Entry具有以下属性:

  NSInteger类型; 
NSDate * timestamp;
NSString * username;
NSString * session;
NSString * body;

其中'type'可以是:

  1  -  message 
2 - 文件传输(然后body表示文档文件夹中的文件名)
3 - 用户加入
4 - 用户离开

我的应用程序还支持多用户聊天左类型)。所有邮件属于同一个会话(仅限多方聊天),将具有有效的会话属性。



在我的聊天记录中,我的问题是如何实现'加载更多'像苹果在短信应用程序:我将查询基于'用户名=%@ AND会话IS NULL''session = %@'以显示历史记录,并使用通过反转的时间戳排序的LIMIT 50。
然后我想要一个按钮加载更多,这将加载接下来的50条消息 - 我不知道如何做它与核心数据。



我的下一个问题是如何显示会话列表。现在使用raw sqlite,我对2个查询执行连接:第一个是每个用户的最后一个消息,第二个是每个多用户会话的最后一个消息。然后我们按日期对它们进行排序。
由于Core Data不支持连接,因此我不确定如何执行此查询。



感谢

解决方案

有一个完全相同的应用程序,这里是我的见解。



首先, coredata和多线程明智地在编码之前。



模型



您正在与Coredata中的实体合作,这可以被视为sqlite中的表,但是以更抽象的方式。您应审核Apple的文档



我们可以在你的案例中找到至少三个不同的实体:User,Conversation和Message。 (注意最后一个,在导入SMS框架时,我有一个名为Message的实体的问题,您应该考虑为实体命名的前缀。)



coredata的一个问题是,你不能直接存储数组(可能是一些未知类型),但无论如何。所以两个解决方案来存储你的用户:在NSString中,当他们将被分隔的彗星和一个简单的正则表达式或拆分将给你的用户数量。



您的模型可能如下所示:

 对话{
messages< - >> Message.conversation
lastMessage< - > Message.whateverName
//可选
用户< - >> User.conversation
}

消息{
conversation<< - > Conversation.messages
whatevername< - > Conversation.lastmessage //无论什么都不重要
}

用户{
conversations<< - >> Conversation.users
}


$ b b

对话必须与消息和消息具有一对多的关系,并且与对话具有一对一的关系。



- EDIT / p>

如果要显示会话的最后一条消息,就像消息应用程序(或我的应用程序),您可以添加一个消息关系。它不会在数据库/ coredata中存储两次消息。事实上,你创建一个coredata对象(在这种情况下是一个消息),并将其添加到对话中,内部发生的是,一个对话存储该对象的coredata ID。为此消息添加一个关系(lastMessage)将只存储另一个ID,而不是另一个对象。



- EDIT结束



用户略有不同,



您可以根据需要添加多个属性,因此您可以添加多个属性,


  1. 实施

然后在你的代码中,如果你想模仿iMessage的行为,这里是我做了:



在第一个控制器,你可以看到所有的对话:使用NSFetchedResultController。



当点击一行时,我所做的是新视图有对话对象和另一个NSFtechedResultController。



如果你想检查我的应用程序看到流动性,转到此链接。



编辑

strong>


  1. 用于查找最后一封对话的代码段

请注意:在找到更好的方法之前(即使用抓取的属性),这是一个临时答案

  NSFetchRequest * req = [[NSFetchRequest alloc] init]; 
[req setEntity:[NSEntityDescription entityForName:@MessageinManagedObjectContext:context]];
[req setPredicate:[NSPredicate predicateWithFormat:@conversation ==%@,self]]; / *从一个对话对象。* /
NSSortDescriptor * sort = [[NSSortDescriptor alloc] initWithKey:@sent_dateascending: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;

- EDIT结束


$


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 switching the engine.

My main table is called Entry with the following properties:

NSInteger type;
NSDate* timestamp;
NSString* username;
NSString* session;
NSString* body;

where 'type' can be:

1 - message
2 - file transfer (which then 'body' represents a file name in the documents folder)
3 - user joined
4 - user left

My app also supports multi-user chat (hence why the 'user joined'/'user left' types). All messages belong to the same conversation (multi-chat only), will have a valid 'session' property.

In my chat history, my problem is how to achieve the 'load more' like Apple did in the SMS app: I will query based on 'username=%@ AND session IS NULL' or 'session=%@' to show that history and use a LIMIT of 50 sorted by reversed 'timestamp'. I then want to have a button "Load more" which will load the next 50 messages - I'm not sure how to do it with Core Data.

My next question is how to show the list of conversations. Right now with raw sqlite, I perform a join on 2 queries: the first is the last message of each user and the second is the last message of each multi-user conversation. I then sort them all by date. Since Core Data does not support joins, I'm not sure how to perform this query.

Thanks

解决方案

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

这篇关于使用Core Data设计聊天应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆