2012-03-29 115 views
8

我正在編寫一個聊天應用程序,並且正在更改我的數據庫以使用核心數據。我目前直接使用sqlite,但我想利用iCloud功能,因此我正在切換引擎。設計使用核心數據的聊天應用程序

我的主要表被稱爲具有以下屬性條目:

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

其中「類型」可以是:

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

我的應用也支持多用戶聊天(因此爲什麼「用戶加入'/'用戶左''類型)。所有消息屬於同一個會話(僅限多聊天),將具有有效的「會話」屬性。

在我的聊天記錄,我的問題是如何實現「負載更」像蘋果的短信應用程序所做的:我會查詢基於'username=%@ AND session IS NULL''session=%@'表明歷史,並使用反向排序50 LIMIT「時間戳」。 然後我想要一個按鈕「加載更多」,這將加載下50封郵件 - 我不知道如何使用核心數據。

我的下一個問題是如何顯示對話列表。現在使用原始的sqlite,我對2個查詢執行連接:第一個是每個用戶的最後一條消息,第二個是每個多用戶對話的最後一條消息。然後我按日期排列它們。 由於核心數據不支持連接,我不知道如何執行此查詢。

謝謝

回答

14

有一個應用程序,做同樣的事情,這裏是我的見解。

首先,您應該在編碼之前明智地考慮coredata和多線程。如果你需要幫助,請告訴我。

模型

您在Coredata實體,可以考慮像SQLite中的表,但在一個更抽象的方式。你應該爲review Apple's documentation

我們可以在您的案例中找到至少三個不同的實體:用戶,對話和消息。 (請注意最後一個,在導入SMS Framework時我遇到了一個名爲Message的實體問題,您應該考慮在實體名稱前加上..)

coredata的一個問題是,您無法直接存儲數組(可能有一些未知類型),但無論如何。所以兩種解決方案來存儲用戶:無論是在時,他們會用逗號和一個簡單的正則表達式或拆分會給你的用戶數量來界定的的NSString ..

所以你的模型可能看起來像:

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 
} 

會話必須與消息和消息具有多對多的關係才能與對話建立一對一的關係。

--edit

如果你想顯示就像該消息應用程序(或我的應用程序)的對話的最後消息,您可以添加與消息一一對應關係。它不會在數據庫/ coredata中存儲兩次消息。事實上,你創建一個coredata對象(在這種情況下是一條消息),並將其添加到對話中,內部發生的是對話存儲該對象的coredata ID。爲此消息添加一個關係(lastMessage)將僅存儲另一個ID,而不是另一個對象。

編輯

用戶--end略有不同,因爲它們可以是多個對話(因爲組羣會話)的一部分,這就是爲什麼你需要一個多到許多關係的船。

您可以根據需要添加任意數量的屬性,但這是最低要求!

  1. 實施

然後在你的代碼,如果你想模仿iMessage的行爲,這裏是我做過什麼:

第一控制器,在那裏你可以看到所有的談話

:使用NSFetchedResultController。查詢應該只關於實體對話。

當單擊一行時,我所做的是新視圖具有會話對象和另一個NSFtechedResultController。然後我只查詢實體消息,但用謂詞指定我只想要這個對話。

如果你想檢查我的應用程序,看流動性,go to this link.

編輯

  1. 代碼片段找到對話的最後消息

請注意:這在找到一個更好的方法來做它之前(即使用提取的屬性時)是臨時答案

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

希望這有助於!

皮埃爾

+0

我按照你的建議去了,但是在閱讀對話列表時 - 我怎樣才能得到最後一條消息在那裏顯示(就像你在「消息」屏幕中做的那樣)。謝謝。 – 2012-07-20 15:21:33

+0

嗨吉拉德 我稍微編輯了我的答案。 基本上,只需添加一個名爲lastMessage的一對一關係或任何你想要的。 每當您收到新消息/ delete_the_last_one時,只需更新lastMessage字段即可。 如果你不是增加額外關係的粉絲,我可以猜測每次對話都會挖掘NSFetchRequest以查找最後一條消息,但這可能會非常糟糕,性能也很明智。 希望能幫助 – Pierre 2012-07-23 09:57:48

+0

非常感謝皮埃爾 - 這就是我最終做的。刪除郵件時我有一個小問題(我需要手動識別最新郵件並更新我的會話對象),但至少我可以正確地獲取歷史記錄。謝謝!!! – 2012-07-23 23:35:09

1

首先,你的心智模式是錯的。您不應該將核心數據視爲SQL數據庫。是的,大多數情況下它使用SQL,但它僅僅是一個實現細節。你應該考慮對象圖。

接下來,針對您的「50項」問題,查看NSFetchRequest。您可以告訴它從哪裏開始(fetchOffset)以及要提取多少項(fetchLimit)。還有其他的選擇。如果您的項目總數相對較少,那麼您可以只讀取整個數組(並且一次僅錯誤很多 - 請參閱fetchBatchSize)。

對於您的「連接」,請考慮對象如何相互關聯,而不是數據庫表連接。不幸的是,我不明白你試圖用這部分問題來達到什麼目的。但是,在形成謂詞時,可以使用點符號模仿「連接」表。

編輯

當你創建一個會話對象,可以包括一個一對多的關係,以類似「參與者」,這將是一個集所有參與該對話的用戶。反過來也是一個包含用戶參與的所有對話的「用戶」中的一對多關係(我假設你的數據庫有多個用戶?)。

因此,要獲得所有在一個特定的用戶參與,你可以不喜歡取的「參與者」與同類謂詞的談話,以「ALL participants.username =%@」

+0

對於問題的第二部分:我想要做的是列出所有會話(向他們展示的列表,用戶可以在其中單擊,然後擴大到看到完整的對話) 。它與iMessage類似。我想顯示每個獨特對話的最後一條消息。我不能通過用戶名進行分組,因爲用戶可能會出現兩次(一次在單個聊天中,一次在組聊天中) – 2012-05-08 15:55:55

+0

您想要顯示所有對話的最後一條消息,或僅顯示特殊用戶是最後一條消息的消息?對不起,我不使用聊天客戶端,所以我不熟悉這個比喻。 – 2012-05-08 18:51:00

+0

假設我與用戶A(我們交換了100條消息)的對話,以及與用戶B(50條消息)的另一對話和與用​​戶A/B同時(10條消息)的組聊天:我想顯示一個列表,其中包含3個項目(A,B,A/B)。如果您點擊第一個條目 - 您將看到100條消息歷史記錄,點擊第二條將顯示50條消息歷史記錄,點擊第三條將顯示10條消息。我期待模仿iMessage。 – 2012-05-08 19:01:59