Разработка приложения для чата с использованием Core Data - PullRequest
8 голосов
/ 30 марта 2012

Я пишу приложение для чата, и я нахожусь в процессе изменения своей базы данных для использования Core Data. В настоящее время я использую sqlite напрямую, но хочу воспользоваться функцией iCloud, поэтому я переключаю движок.

Моя основная таблица называется Entry со следующими свойствами:

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

Мое приложение также поддерживает многопользовательский чат (следовательно, почему типы «пользователь присоединился» / «пользователь ушел»). Все сообщения, относящиеся к одному разговору (только для нескольких чатов), будут иметь действительное свойство сеанса.

В моей истории чата моя проблема заключается в том, как добиться «загрузки большего», как это делала Apple в приложении SMS: я буду запрашивать на основе 'username=%@ AND session IS NULL' или 'session=%@', чтобы показать эту историю, и использовать ПРЕДЕЛ 50, отсортированный по обратной «отметке времени». Затем я хочу иметь кнопку «Загрузить еще», которая загрузит следующие 50 сообщений - я не уверен, как это сделать с Core Data.

Мой следующий вопрос - как показать список разговоров. Прямо сейчас с raw sqlite я выполняю объединение по 2 запросам: первый - последнее сообщение каждого пользователя, а второй - последнее сообщение каждого многопользовательского разговора. Затем я сортирую их все по дате. Поскольку Core Data не поддерживает объединения, я не уверен, как выполнить этот запрос.

Спасибо

Ответы [ 2 ]

14 голосов
/ 28 мая 2012

Имея приложение, которое делает то же самое, вот мои идеи.

Прежде всего, вы должны продумать coredata и многопоточность, прежде чем кодировать.Если вам нужна помощь, дайте мне знать.

Модель

Вы работаете с сущностями в Coredata, которые можно рассматривать как таблицы в sqlite, но более абстрактно.Для этого вам следует просмотреть документацию Apple .

В вашем случае мы можем найти как минимум три различных объекта: Пользователь, Разговор и Сообщение.(будьте осторожны с последним, у меня возникла проблема с сущностью под названием Message при импорте SMS Framework, вы должны рассмотреть вопрос о добавлении префикса имени сущности ..)

Проблема с coredata заключается в том, что вы не можетехранить напрямую массивы (может быть с неизвестным типом), но в любом случае.Итак, два решения для хранения ваших пользователей: либо в строке NSSt, когда они будут разделены запятыми, и простое регулярное выражение или разделение даст вам количество пользователей ..

, чтобы ваша модель могла выглядеть так:

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
}

Разговор должен иметь отношение «ко-многим» с «Сообщением», а «Сообщение» - отношение «один к одному» с «Разговором».

- РЕДАКТИРОВАТЬ

Если вы хотитечтобы отобразить последнее сообщение разговора, как сообщение «Приложение» (или мое приложение), вы можете добавить одну связь с сообщением.Это не будет хранить сообщение дважды в базе данных / coredata.Действительно, вы создаете объект coredata (в данном случае сообщение) и добавляете его в диалог, что происходит в том, что диалог сохраняет идентификатор coredata для этого объекта.Добавление одного отношения для этого сообщения (lastMessage) будет хранить только другой идентификатор, а не другой объект.

- конец EDIT

Пользователи немного отличаются, потому что они могут быть частью нескольких бесед (из-за групповой беседы), поэтому вам нужно многоОтношение ко многим.

Вы можете добавить столько атрибутов, сколько хотите, но это минимальное требование!

  1. Реализация

тогда в вашемкод, если вы хотите имитировать поведение iMessage, вот что я сделал:

в первом контроллере, где вы можете увидеть весь диалог: используйте NSFetchedResultController.Запрос должен касаться только сущности Conversation.

При нажатии на строку я сделал следующее: у нового представления есть объект диалога и другой NSFtechedResultController.Затем я запрашиваю только сообщение сущности, но с предикатом, указывающим, что я хочу только эту беседу.

Если вы хотите проверить мое приложение, чтобы увидеть текучесть, перейдите по этой ссылке.

РЕДАКТИРОВАТЬ

  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;

- конец EDIT

Надеюсь, эта помощь!

Pierre

1 голос
/ 08 мая 2012

Во-первых, у вас неправильная ментальная модель. Вы не должны думать о базовых данных как о базе данных SQL. Да, в большинстве случаев он использует SQL, но это просто деталь реализации. Вы должны думать с точки зрения графов объектов.

Далее, для вашей проблемы "50 предметов", посмотрите NSFetchRequest. Вы можете указать, с чего начать (fetchOffset) и сколько элементов выбрать (fetchLimit). Есть и другие варианты для вас. Если общее количество элементов относительно невелико, вы можете просто извлечь весь массив (и только столько ошибок одновременно - см. FetchBatchSize).

Для вашего "объединения" рассмотрите, как объекты связаны друг с другом, а не объединения таблиц базы данных. К сожалению, я не понимаю, чего вы пытаетесь достичь с помощью этой части вопроса. Однако вы можете имитировать «объединенные» таблицы, используя точечные обозначения при формировании предиката.

EDIT

Когда вы создаете объект разговора, вы можете включить отношение «многие-многие» к чему-то вроде «участники», которое будет представлять собой совокупность всех пользователей, которые участвовали в этом разговоре. Обратное также будет отношением «ко-многим» в «user», в котором содержатся все разговоры, в которых участвовал пользователь (я предполагаю, что в вашей базе данных несколько пользователей ???).

Таким образом, чтобы получить все разговоры, в которых участвовал конкретный пользователь, вы можете сделать что-то вроде извлечения для «Участника» с предикатом, похожим на «ALL members.username =% @»

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...