Во многих из приведенных ответов содержится некоторая полезная информация, но ни один из них не дает полного ответа на вопрос.
Вопрос касается передачи информации между контроллерами представления. В приведенном конкретном примере запрашивается передача информации между представлениями, но с учетом самооценки новизны iOS первоначальный плакат, скорее всего, подразумевал между viewControllers, а не между представлениями (без какого-либо участия ViewControllers). Кажется, что все ответы сосредоточены на двух контроллерах представления, но что, если приложение развивается, чтобы задействовать более двух контроллеров представления в обмене информацией?
На оригинальном плакате также спрашивалось о синглетах и использовании AppDelegate . На эти вопросы нужно ответить.
Чтобы помочь кому-то еще, смотрящему на этот вопрос, который хочет получить полный ответ, я попытаюсь дать его.
Сценарии применения
Вместо того, чтобы проводить весьма гипотетическое, абстрактное обсуждение, оно помогает иметь в виду конкретные применения. Чтобы помочь определить ситуацию с двумя представлениями контроллера и ситуацией с более чем двумя представлениями, я собираюсь определить два конкретных сценария применения.
Сценарий один: максимум два контроллера представления когда-либо должны обмениваться информацией.
Смотрите диаграмму один.
В приложении есть два контроллера вида. Существует ViewControllerA (форма ввода данных) и View Controller B (список продуктов). Элементы, выбранные в списке продуктов, должны соответствовать элементам, отображаемым в текстовом поле в форме ввода данных. В этом сценарии ViewControllerA и ViewControllerB должны взаимодействовать напрямую друг с другом, а не с другими контроллерами представления.
Сценарий два : более двух контроллеров представления должны совместно использовать одну и ту же информацию.
См. Диаграмму два.
В приложении есть четыре контроллера вида. Это приложение на основе вкладок для управления домашним инвентарем. Три контроллера представления представляют по-разному отфильтрованные представления одних и тех же данных:
- ViewControllerA - Предметы роскоши
- ViewControllerB - Незастрахованные товары
- ViewControllerC - Инвентарь всего дома
- ViewControllerD - Добавить новый элемент формы
Каждый раз, когда отдельный элемент создается или редактируется, он также должен синхронизироваться с другими контроллерами представления. Например, если мы добавляем лодку в ViewControllerD, но она еще не застрахована, тогда лодка должна появиться, когда пользователь перейдет к ViewControllerA (Предметы роскоши), а также ViewControllerC (Весь инвентарь дома), но не когда пользователь перейдет к ViewControllerB (не застрахованные предметы). Нам нужно заботиться не только о добавлении новых элементов, но и об удалении элементов (которые могут быть разрешены с любого из четырех контроллеров представления) или редактировании существующих элементов (что можно разрешить из «Формы добавления нового элемента», с целью повторного использования того же самого). для редактирования).
Поскольку все контроллеры представления должны совместно использовать одни и те же данные, все четыре контроллера представления должны оставаться в синхронизации, и, следовательно, должна быть какая-то связь со всеми другими контроллерами представления, всякий раз, когда какой-либо один контроллер представления изменяет базовый данные. Должно быть совершенно очевидно, что мы не хотим, чтобы каждый контроллер представления взаимодействовал напрямую друг с другом в этом сценарии. В случае, если это не очевидно, рассмотрим, было ли у нас 20 различных контроллеров представления (а не только 4). Насколько сложно и подвержено ошибкам уведомлять каждый из 19 контроллеров представления каждый раз, когда один контроллер представления вносит изменения?
Решения: делегаты и шаблон наблюдателя и синглтоны
В первом сценарии у нас есть несколько жизнеспособных решений, как и другие ответы
- перетекает
- Делегаты
- установка свойств на контроллерах вида напрямую
- NSUserDefaults (на самом деле плохой выбор)
Во втором сценарии у нас есть другие жизнеспособные решения:
- Шаблон наблюдателя
- Одиночки
A singleton - это экземпляр класса, который является единственным экземпляром, существующим в течение его жизни. Синглтон получил свое название от того факта, что это единственный экземпляр. Обычно разработчики, которые используют синглтоны, имеют специальные методы класса для доступа к ним.
+ (HouseholdInventoryManager*) sharedManager; {
static dispatch_once_t onceQueue;
static HouseholdInventoryManager* _sharedInstance;
// dispatch_once is guaranteed to only be executed once in the
// lifetime of the application
dispatch_once(&onceQueue, ^{
_sharedInstance = [[self alloc] init];
});
return _sharedInstance;
}
Теперь, когда мы понимаем, что такое синглтон, давайте обсудим, как синглтон вписывается в схему наблюдателя. Шаблон наблюдателя используется для того, чтобы один объект реагировал на изменения другого объекта. Во втором сценарии у нас есть четыре разных контроллера представления, которые все хотят знать об изменениях в базовых данных. «Базовые данные» должны принадлежать одному экземпляру, одиночке. «Знать об изменениях» достигается путем наблюдения изменений, внесенных в синглтон.
Приложение для домашнего инвентаризации будет иметь единственный экземпляр класса, который предназначен для управления списком инвентарных предметов. Менеджер будет управлять коллекцией предметов домашнего обихода. Ниже приведено определение класса для менеджера данных:
#import <Foundation/Foundation.h>
@class JGCHouseholdInventoryItem;
@interface HouseholdInventoryManager : NSObject
/*!
The global singleton for accessing application data
*/
+ (HouseholdInventoryManager*) sharedManager;
- (NSArray *) entireHouseholdInventory;
- (NSArray *) luxuryItems;
- (NSArray *) nonInsuredItems;
- (void) addHouseholdItemToHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) editHouseholdItemInHomeInventory:(JGCHouseholdInventoryItem*)item;
- (void) deleteHoueholdItemFromHomeInventory:(JGCHouseholdInventoryItem*)item;
@end
Когда коллекция предметов домашнего инвентаря изменяется, контроллеры представления должны быть осведомлены об этом изменении. Приведенное выше определение класса не дает понять, как это будет происходить. Нам нужно следовать схеме наблюдателя. Контроллеры представления должны формально соблюдать sharedManager. Есть два способа наблюдать за другим объектом:
- Наблюдение значения ключа (KVO)
- NSNotificationCenter.
Во втором сценарии у нас нет ни одного свойства HouseholdInventoryManager, которое можно было бы наблюдать с помощью KVO. Поскольку у нас нет единственного свойства, которое легко наблюдать, шаблон наблюдателя в этом случае должен быть реализован с использованием NSNotificationCenter. Каждый из четырех контроллеров представления будет подписываться на уведомления, а sharedManager будет отправлять уведомления в центр уведомлений, когда это необходимо. Менеджеру инвентаря не нужно ничего знать о контроллерах представления или экземплярах каких-либо других классов, которые могут быть заинтересованы в знании, когда изменяется коллекция предметов инвентаря; NSNotificationCenter заботится об этих деталях реализации. Контроллеры представления просто подписываются на уведомления, а менеджер данных просто публикует уведомления.
Многие начинающие программисты пользуются тем, что в жизни приложения всегда есть ровно один Application Delegate , который доступен во всем мире. Начинающие программисты используют этот факт для помещения объектов и функций в appDelegate для удобства доступа из любой точки приложения. Тот факт, что AppDelegate является синглтоном, не означает, что он должен заменить все остальные синглтоны. Это плохая практика, поскольку она ложится слишком большим бременем на один класс, нарушая хорошие объектно-ориентированные практики. Каждый класс должен иметь четкую роль, которую легко объяснить, часто просто именем класса.
Каждый раз, когда ваш Application Delegate начинает раздуваться, начинайте удалять функциональность в одиночку. Например, основной стек данных не следует оставлять в AppDelegate, а вместо этого следует помещать в его собственный класс, класс coreDataManager.
Ссылки