Какой шаблон следует использовать для редактирования свойств с помощью контроллера модального вида на iPhone? - PullRequest
2 голосов
/ 26 апреля 2010

Я ищу хороший шаблон для выполнения базового редактирования свойств через модальное представление на iPhone.

Предположим, я собираю приложение, которое работает как приложение Контакты. Контроллер представления подробностей отображает все свойства контакта в UITableView. Когда UITableView переходит в режим редактирования, в ячейках отображается значок раскрытия. Щелчок по ячейке заставляет модальный контроллер представления «редактор» отображать представление, которое позволяет пользователю изменять выбранное свойство. Это представление часто будет содержать только одно текстовое поле или средство выбора. Пользователь нажимает кнопку Отмена / Сохранить, и представление «редактор» закрывается, а представление «подробности» обновляется.

В этом сценарии, какое представление отвечает за обновление модели?

Представление «редактор» может обновлять свойство напрямую, используя Key-Value Coding. Это появляется в примере CoreDataBooks. На некотором уровне это имеет смысл для меня, поскольку оно рассматривает свойство как модель для контроллера представления редактора.

Однако это не тот шаблон, который предлагается в Руководстве по программированию View Controller. Предполагается, что контроллер представления «редактор» должен определить протокол, который принимает контроллер «детали». Когда пользователь указывает, что он завершил редактирование, контроллер представления «detail» вызывается обратно с введенным значением и отклоняет представление «editor». Используя этот подход, контроллер «detail» обновляет модель. Этот подход кажется проблематичным, если вы используете одно и то же представление «редактор» для нескольких свойств, поскольку существует только один метод обратного вызова.

Хотелось бы получить отзывы о том, какой подход работает лучше всего.

Ответы [ 2 ]

0 голосов
/ 26 апреля 2010

Я не думаю, что какие-либо примеры Apple (или чьи-либо еще) на самом деле показывают вам, как структурировать приложение в реальном мире. Вместо этого каждый пример представляет собой просто тестовый набор, который показывает вам, как использовать одну конкретную функцию API, но не обращает внимания на то, как эта функция действительно интегрируется с чем-либо еще. Модели данных даны особенно короткие смены.

Я предпочитаю проект, в котором модель данных является основой приложения, в котором находятся все пары вид-контроллер / вид. Контроллеры представления не обмениваются данными друг с другом напрямую, а взаимодействуют через модель данных. Модель данных отслеживает, над какой информацией в данный момент работает приложение и, следовательно, какие данные нужны каждому конкретному контроллеру представления в любой момент времени.

Давайте в качестве примера рассмотрим приложения типа диспетчера контактов. Основой модели данных будет список объектов контактов, каждый из которых, в свою очередь, будет содержать атрибуты контакта. Модель данных полностью контролирует доступ к данным и отслеживает, какие данные используются в настоящее время. Пользовательский интерфейс является иерархическим, так что пользователь сначала видит список всех контактов в masterView, затем детали каждого контакта в contactDetailView, а затем может редактировать каждый атрибут контакта в пользовательском представлении редактирования атрибута для каждого типа данных, чтобы nameEditView, phoneDetailView, emailEditView и т. д. Каждый из них имеет masterVC контроллера сопряженного представления, contactDetailVC, nameEditVC и т. д.

Чтобы построить свое табличное представление, masterVC запрашивает модель данных о количестве контактов, их делениях на секции, а затем запрашивает каждый конкретный контактный объект на каждом конкретном пути индекса, чтобы он мог отобразить таблицу. Когда пользователь выбирает строку таблицы, masterVC сообщает модели данных, какой контактный объект был выбран, отправляя ему индекс. Затем masterVC выдвигает контакт подробно. Больше ничего не делает.

Когда активируется contactDetailVC, он запрашивает модель данных для текущего активного объекта Contact. Он не знает и не заботится о том, как был выбран текущий контакт, и даже о том, какой вид / ВК предшествовал ему. Модель данных возвращает текущий активный контакт. Когда пользователь выбирает поле, contactDetailVC сообщает модели данных, какой атрибут контакта был выбран, а затем помещает соответствующий редактор VC в стек.

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

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

Этот тип модели позволяет легко приостановить, возобновить или перезапустить приложение до его предыдущего состояния. Поскольку каждый вид / VC самодостаточен, при перезапуске приложения вы просто помещаете все представления в стек без анимации, а последнее нажатие выскакивает полностью заполненным данными, даже если пользователь ничего не выбрал в предыдущих представлениях и действительно сделал даже не вижу их.

Он также защищает пользователя от потери данных в случае сбоя, поскольку каждый VC сохраняет свои данные и состояние приложения каждый раз, когда он нажимает или выскакивает. Легко добавить дополнительное представление / VC, потому что каждый VC должен знать и взаимодействовать только с моделью данных, а не с кучей других VC. Это делает компоненты приложения простыми в использовании в разных версиях приложения или в разных приложениях.

Edit:

Вы просто жестко задаете код, если заявления для сопряжения атрибутов с правильным редактором, или вы делать что-то более динамичное на основе метаданные сущности / атрибута?

В большинстве наиболее распространенных схем сущность «Контакт» может иметь переменное количество телефонов, электронных писем или других полей данных, поэтому каждый атрибут фактически будет отдельной сущностью, и Контакт будет иметь отношения, указывающие на эти сущности. Когда пользователь выбирает этот контакт для редактирования в ContactDetailView, модель данных просто помечает NSManagedObject, представляющий требуемый атрибут контакта. Это можно сделать, установив атрибут наподобие lastChosenAttribute или сохранив URI для объекта. Когда загрузится представление редактора, будет сложно запрограммировать модель данных для «lastChosenAttribute» и получить NSManagedObject для номера телефона, электронной почты и т. Д. Редактор внесет изменения в этот объект, и они автоматически сохранятся обратно контакт.

Для данных, которые являются единичными, таких как имя или компоненты имени, модель данных предоставит editorVC контактную сущность, и editorVC будет жестко задан для запроса у контактного объекта определенного атрибута.

0 голосов
/ 26 апреля 2010

Это сложный вызов - рекомендация View Controller Guide кажется более концептуальной, но другой метод может быть проще, особенно если вы используете Core Data. Чтобы дать общее обобщенное мнение, я бы сказал, используйте ваш первый метод, если вы используете Core Data, поскольку управляемые объекты по своей природе имеют собственный контекст и могут обновлять себя (а классы, такие как NSFetchedResultsController, могут автоматически отвечать на обновления).

Если вы не используете Core Data, я бы согласился с «официальной» рекомендацией, поскольку она упрощает управление обновленными свойствами вручную. Что касается заботы о нескольких свойствах, то, безусловно, возможно иметь несколько методов делегата и вызывать соответствующий. Например:

//if property is an address
if ([self.delegate respondsToSelector:@selector(editorView:didUpdateAddress:)])
    [self.delegate editorView:self didUpdateAddress:theAddress];

//if property is a name
if ([self.delegate respondsToSelector:@selector(editorView:didUpdateName:)])
    [self.delegate editorView:self didUpdateName:theName];

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

...