Статьи

Передача данных с помощью NSNotification между ViewControllers в Swift 3

Эта статья была первоначально опубликована на iOS Geek Community .

Сегодня давайте поговорим о том, как и почему мы используем NSNotification для передачи данных и связи / уведомления между классами и структурами. Кстати, NSNotification , в отличие от своего названия, не имеет ничего общего с Push Notification — ошибкой новичка 101 (я).

Да, в Swift есть много способов передачи данных: Delegate , Key-Value Observing , Segue и NSNotification , Target-Action , Callbacks . Однако у каждого есть свои плюсы и минусы. Они как столовая посуда. Например, я бы не использовал палочки для еды — хотя это чертовски хорошо — пить суп.

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

Что я думаю, вы узнаете

В этом уроке вы узнаете 2 вещи. Во-первых, вы поймете, как «уведомлять» другие контроллеры представления или внутри одного контроллера представления. Во-вторых, вы поймете силу NSNotification и его слабые стороны.

UI Component

Есть два вида контроллеров. FirstVC и SecondVC . Я предполагаю, что вы уже знаете, как встроить UINavigationController и подключить IBOutlets и IBActions и так далее.

SecondVC уведомит FirstVC . Когда я говорю «уведомить», это все равно что тыкать. Это не отправка каких-либо данных, но, конечно, мы можем. Я объясню, как отправить данные чуть позже в этой статье. Пример ниже аналогичен тому, как пользователь обновляет профиль в Facebook или Instagram. Я не использую UITableView так как это было бы излишним для объяснения концепции.

введите описание изображения здесь

Прежде чем мы начнем, давайте представим, как бы мы реализовали это на очень высоком уровне. Представьте, что два viewcontrollers похожи на красивую пару. У них обоих есть смартфоны (объекты NSNotification), чтобы общаться друг с другом. Во-вторых, каждый смартфон имеет две функции: получение и отправка данных . Наконец, чтобы найти устройство друг друга, у них есть общий секретный ключ . Тем не менее, решать друг другу, хочет ли кто-нибудь ответить на звонок или просто проигнорировать.

Поскольку у нас есть общее понимание того, как они общаются друг с другом, давайте погрузимся в Swift ☝️

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

 import UIKit let myNotificationKey = "com.bobthedeveloper.notificationKey" class SecondVC: UIViewController {} 

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

Теперь пришло время прикрепить смартфон. Давайте назовем это наблюдателем. Наблюдатель будет иметь четыре параметра. Он спросит Observer который будет self так как вы SecondVC смартфон к SecondVC . Во-вторых, Selector , это функция, которая запускается при уведомлении. В-третьих, имя, которое относится к секретному коду. Наконец, object который я объясню позже при работе с FirstVC. Просто положите nil на данный момент.

 class SecondVC: UIViewController { @IBOutlet weak var secondVCLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(doThisWhenNotify), name: NSNotification.Name(rawValue: myNotificationKey), object: nil) } func doThisWhenNotify() { print("I've sent a spark!") } } 

Я не понимаю значения свойства type по default потому что в руководстве по API нет описания. Это говорит, *

«Обзор недоступен» — Apple

В любом случае, у SecondVC есть смартфон / наблюдатель, пора отправлять / уведомлять, когда нажимается кнопка

 @IBAction func tabToNotifyBack(_ sender: UIButton) { NotificationCenter.default.post(name: Notification.Name(rawValue: myNotificationKey), object: self) secondVCLabel.text = "Notification Completed!" } 

В этом контексте object относится к отправителю. Поскольку SecondVC уведомляет себя, он self .

Поскольку FirstVC еще не зарегистрировал наблюдателя, искра / тыкание не повлияет на него. Я уже упоминал ранее, партнер имеет право поднять трубку или просто проигнорировать. В iOS мы назвали это «слабой связью». В отличие от отправки данных между контроллерами представления с использованием делегата / протокола, не происходит сумасшедшего связывания. Я знаю, что некоторые из вас, ребята, в замешательстве. Я планирую написать статью о том, как передавать данные с использованием делегата в будущем. Также я буду обсуждать delegate vs NSNotification

Ресурс
Передача данных между ViewControllers в Swift 3 без Segue ( YouTube )

Время получать

FirstVC довольно прост. Он добавит смартфон и прислушивается к искре, если у него такой же секретный ключ.

 import UIKit class FirstVC: UIViewController { @IBOutlet weak var FirstVCLabel: UILabel! override func viewDidLoad() { super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(doAfterNotified), name: NSNotification.Name(rawValue: myNotificationKey), object: nil) } func doAfterNotified() { print("I've been notified") FirstVCLabel.text = "Damn, I feel your spark" } } 

Теперь поговорим об object который является одним из параметров, которые я пропустил ранее. Если он равен nil , вам все равно, откуда / куда смартфон отправляет данные, пока у вас есть секретный ключ. Я никогда ничего не использовал
кроме nil так что, возможно, те, кто использовал его раньше, могут мне помочь. Другими словами, я не знаю, как реализовать

Теперь это должно выглядеть примерно так.

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

Исходный код
Github

Передача данных

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

В SecondVC вместо старого доброго способа

 // Pass Spark NotificationCenter.default.post(name: NSNotification.Name(rawValue: myNotificationKey), object: nil) 

Теперь вы можете отправить искру, которая содержит словарь

 // Pass Data NotificationCenter.default.post(name: NSNotification.Name(rawValue: myNotificationKey), object: nil, userInfo: ["name":"Bob"]) 

В FirstVC , под viewDidLoad , вы вставите это вместо

 NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: myNotificationKey), object: nil, queue: nil, using:catchNotification) 

Я не собираюсь говорить об queue . Если поставить nil , задача получения происходит синхронно. Другими словами, если это не nil , FirstVC может получать данные с помощью Grand Central Dispatch . Если вы не понимаете GCD, не волнуйтесь. Я написал две статьи для вас. Может быть, я должен написать о том, как передавать данные асинхронно с помощью GCD! Это было бы интересно.

Ресурсы
Введение в Grand Central Dispatch в Свифте 3 ( Средний )

Интерфейс и сеть, как босс в Swift 3 ( средний )

Вы заметили что-то другое. Это верно catchNotification Эта функция будет использовать искру, которая содержит userInfo! catchNotification выглядит примерно так

 func catchNotification(notification:Notification) -> Void { guard let name = notification.userInfo!["name"] else { return } FirstVCLabel.text = "My name, \(name) has been passed! " } 

Как только кнопка из SecondVC нажата, catchNotification запускается автоматически и содержит userInfo переданный из SecondVC . Если вы не понимаете, как разворачивать опциональные файлы, используя инструкцию охраны, не стесняйтесь проверить мое видео ниже.

Ресурс
Охранное заявление ( YouTube )

Итак, наконец, это должно выглядеть примерно так

Ресурс
Исходный код

Удалить Обозреватель / Смартфон

Если вы хотите удалить любого наблюдателя, когда представление было отклонено, просто вставьте приведенный ниже код в FirstVC или любые другие контроллеры представления.

 override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(true) NotificationCenter.default.removeObserver(self) } 

Последние замечания

Эта статья заняла немного больше времени, чем я ожидал. Но так приятно писать и общаться с большим количеством людей. Спасибо всем за то, что прошли весь путь ко дну Очень признателен. ?

Рекомендуемые статьи :

Не стесняйтесь проверить рекомендуемые статьи:

10 основных правил для разработчиков iOS

Введение в Grand Dispatch Central с Бобом