2012-03-29 2 views
8

Ich schreibe eine Chat-App und bin dabei, meine Datenbank zu ändern, um Core Data zu verwenden. Ich verwende momentan sqlite direkt, aber ich möchte die iCloud-Funktion nutzen, um die Engine zu wechseln.Design für eine Chat-App mit Core Data

Mein Haupttabelleneintrag mit den folgenden Eigenschaften aufgerufen wird:

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

wo 'Typ' können sein:

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

Meine App unterstützt auch Multi-User-Chat (daher, warum die ‚user verbunden '/' Benutzer links 'Typen). Alle Nachrichten gehören zu derselben Konversation (nur Multichat), haben eine gültige 'Session'-Eigenschaft.

In meinem Chat-Verlauf ist mein Problem, wie die "mehr laden" wie Apple in der SMS-App erreichen: Ich werde basierend auf 'username=%@ AND session IS NULL' oder 'session=%@' abfragen, um diese Geschichte zu zeigen und ein LIMIT von 50 nach umgekehrten sortiert verwenden ' Zeitstempel '. Ich möchte dann eine Schaltfläche "Mehr laden" haben, die die nächsten 50 Nachrichten laden wird - ich bin mir nicht sicher, wie es mit Core Data geht.

Meine nächste Frage ist, wie man die Liste der Gespräche zeigt. Im Moment mit rohen SQLite, führe ich eine Verbindung bei 2 Abfragen durch: die erste ist die letzte Nachricht jedes Benutzers und die zweite ist die letzte Nachricht jeder Mehrbenutzer-Konversation. Ich sortiere sie dann alle nach Datum. Da Core Data Joins nicht unterstützt, bin ich nicht sicher, wie diese Abfrage durchgeführt werden soll.

Danke

Antwort

14

Having eine App, macht genau das gleiche, hier sind meine Einsichten.

Zunächst sollten Sie Coredata und Multithreading mit Bedacht vor dem Codieren betrachten. Wenn Sie Hilfe brauchen, lassen Sie es mich wissen.

Das Modell

Sie sind mit Einrichtungen in Coredata arbeiten, die wie Tabellen in SQLite betrachtet werden können, sondern in einer abstrakteren Art und Weise. Sie sollten review Apple's documentation dafür.

Wir können in Ihrem Fall mindestens drei verschiedene Entitäten finden: Benutzer, Konversation und Nachricht. (Seien Sie vorsichtig mit dem letzten, ich hatte ein Problem mit der Entität mit der Bezeichnung Nachricht beim Importieren des SMS-Frameworks, sollten Sie den Namen der Entität voranstellen.)

Ein Problem mit Coredata ist, dass Sie nicht direkt speichern können Arrays (kann mit einem unbekannten Typ sein), aber trotzdem. So zwei Lösungen, um Ihre Benutzer zu speichern: entweder in einem NSString, wenn sie durch Kommata begrenzt werden und eine einfache regex oder Split geben Sie die Anzahl der Benutzer ..

so könnte Ihr Modell wie folgt aussehen:

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 
} 

Konversation muss eine zu viele Beziehung zu Nachricht und Nachricht eine Eins-zu-Eins-Beziehung zu Konversation haben.

--edit

Wenn Sie die letzte Nachricht einer Konversation ebenso wie die Nachricht App (oder meine app) angezeigt werden sollen, können Sie eine Beziehung mit Nachricht hinzufügen. Die Nachricht wird nicht zweimal in der Datenbank/Coredata gespeichert. In der Tat, Sie erstellen ein Coredata-Objekt (in diesem Fall eine Nachricht) und dass Sie es zu einer Konversation hinzufügen, was im Inneren passiert ist, dass eine Konversation die Coredata-ID für das Objekt speichern. Das Hinzufügen einer Beziehung für diese Nachricht (lastMessage) speichert nur eine andere ID und kein anderes Objekt.

--end von EDIT

Benutzer sind etwas anders, weil sie Teil mehrerer Gespräche sein kann (wegen der Gruppengespräch), das ist, warum Sie eine many-to-many-Beziehung Schiff benötigen.

Sie können so viele Attribute hinzufügen, wie Sie möchten, aber das ist die Mindestanforderung!

  1. Implementierung

dann in Ihrem Code, wenn Sie das Verhalten von iMessage nachahmen wollen, hier ist das, was ich getan habe:

in der ersten Steuerung, wo Sie alle Konversation sehen : Verwenden Sie einen NSFetchedResultController. Die Abfrage sollte nur über die Entität Conversation erfolgen.

Wenn ich auf eine Zeile klicke, habe ich in der neuen Ansicht das Konversationsobjekt und einen weiteren NSFtechedResultController. Ich frage dann nur die Entity Message ab, aber mit einem Prädikat, das angibt, dass ich nur diese Konversation möchte.

Wenn Sie meine App überprüfen, um zu sehen, die Fluidität wollen, go to this link.

EDIT

  1. -Code-Schnipsel die letzte Nachricht eines Gesprächs

Vorsicht zu finden: Diese ist eine vorläufige Antwort, bevor ein besserer Weg gefunden wird, dies zu tun (dh wenn geholte Eigenschaften verwendet werden)

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 von EDIT

Hope this Hilfe!

Pierre

+0

Ich ging mit Ihrem Vorschlag, aber beim Lesen der Konversationsliste - wie bekomme ich die letzte Nachricht dort zu zeigen (wie Sie in der "Nachrichten" -Bildschirm).? Vielen Dank. –

+0

Hallo Gilad Ich habe meine Antwort leicht bearbeitet. Fügen Sie einfach eine Eins-zu-Eins-Beziehung hinzu, die lastMessage oder was auch immer Sie wollen. Jedes Mal, wenn Sie eine neue Nachricht erhalten/delete_the_last_one, aktualisieren Sie einfach das Feld lastMessage. Wenn Sie kein Fan von Hinzufügen einer zusätzlichen Beziehung sind, könnte ich raten in NSFetchRequest für jede Konversation graben, um die letzte Nachricht zu finden, aber es kann sehr schlecht sein, Leistung weise. Hoffe, dass hilft – Pierre

+0

Vielen Dank Pierre - das ist, was ich schließlich getan habe. Ich habe ein kleines Problem beim Entfernen einer Nachricht (ich muss jetzt die letzte Nachricht manuell identifizieren und mein Konversationsobjekt aktualisieren), aber zumindest bekomme ich den Verlauf richtig. Vielen Dank!!! –

1

Zuerst ist Ihr mentales Modell alles falsch. Sie sollten Kerndaten nicht als SQL-Datenbank betrachten. Ja, meistens wird SQL verwendet, es handelt sich jedoch lediglich um ein Implementierungsdetail. Sie sollten in Bezug auf Objektgraphen denken.

Als nächstes, für Ihre "50 Elemente" Problem, schauen Sie auf NSFetchRequest. Sie können angeben, wo (fetchOffset) gestartet werden soll und wie viele Elemente abgerufen werden sollen (fetchLimit). Es gibt auch andere Möglichkeiten für Sie. Wenn Ihre Gesamtanzahl von Elementen relativ klein ist, können Sie einfach das gesamte Array abrufen (und nur so viele Fehler gleichzeitig beheben - siehe fetchBatchSize).

Für Ihre "Join" betrachten, wie Objekte miteinander verknüpft sind, nicht Datenbanktabelle Joins. Leider verstehe ich nicht, was Sie mit diesem Teil der Frage erreichen wollen. Sie können jedoch "verknüpfte" Tabellen nachahmen, indem Sie bei der Bildung Ihres Prädikats die Punktnotation verwenden.

EDIT

Wenn Sie ein Gespräch Objekt erstellen, können Sie eine n-Beziehung zu so etwas wie „Teilnehmer“ enthalten, die eine Reihe von alle Nutzer sein würde, die in diesem Gespräch teil. Die Umkehrung wäre auch eine to-many-Beziehung in "user", die alle Konversationen enthält, an denen der Benutzer teilgenommen hat (ich nehme an, dass Ihre Datenbank mehrere Benutzer hat).

Also, um alle Gespräche, in denen ein bestimmter Benutzer teilgenommen haben, Sie so etwas wie holen auf „Teilnehmer“ mit einem Prädikat tun könnte, ähnlich wie „ALL participants.username =% @“

+0

Für den zweiten Teil der Frage: Was ich versuche zu tun, alle Gespräche zur Liste (eine Liste von ihnen zu zeigen, wo ein Benutzer klicken kann, und erweitern Sie dann das vollständige Gespräch zu sehen) . Es ist ähnlich wie iMessage. Ich möchte die letzte Nachricht jeder einzelnen Konversation anzeigen. Ich kann nicht nach einem Benutzernamen gruppieren, da ein Benutzer zweimal erscheint (einmal in einem Chat und einmal in einem Gruppenchat). –

+0

Sie möchten die letzte Nachricht aller Konversationen anzeigen, oder nur diejenigen, bei denen ein spezieller Benutzer die letzte Nachricht war ? Tut mir leid, ich benutze keine Chat-Clients, daher kenne ich die Analogie nicht. –

+0

Angenommen, ich habe eine Konversation mit Benutzer A (wir tauschten 100 Nachrichten) und eine Konversation mit Benutzer B (50 Nachrichten) und eine Gruppenchat mit beiden Benutzer A/B gleichzeitig (10 Nachrichten): Ich möchte eine Liste mit 3 anzeigen Gegenstände (A, B, A/B). Wenn Sie auf den ersten Eintrag klicken, wird der Verlauf der 100 Nachrichten angezeigt. Wenn Sie auf den zweiten Eintrag klicken, wird der Verlauf der 50 Nachrichten angezeigt. Wenn Sie auf den dritten Eintrag klicken, werden 10 Nachrichten angezeigt. Ich versuche, iMessage nachzuahmen. –