NSKeyValueObserving

Доброговременисуток,Дорогиедрузья! (нет)

С. Key-Value Observing (KVO) Key-Value Observing этоважнаяконцепция,которойоченьнемногиеразработчикипользуются。 APIэтойконцепциидостаточнопрост。 Онпозволяетуведомлятьобъектыприизменениисостояниядругогообъекта。 Этозвучиточеньполезно!

Key-Value Observing реализуетсяпосредствомпротоколаNSKeyValueObserving。 ,тотпротокол,какуказановдокументации🍏,являетсянеофициальным。 КлассNSObjectужереализуетпротоколNSKeyValueObservingилюбойкласс,которыйнаследуетсяотNSObject такжереализуетэтотпротокол。 UIKitнереализоо Foundation (Военинреализуютэтотпротокол)和Воеклассы。 Ноэтоможноисправить😬。

c Key-Value Observing на примере。 Xcodeисоздадим Single View Application注释。 Послесоздадимдвафайла(класса),которыебудутнаследоватьсяотNSObject:

Имплементируем Configuration

О键值Key-Value Observing проста。 Когдаобъектдобавляетсявкачественаблюдателядляопределенноооне Несмотрянато,чтоAPIпротоколаNSKeyValueObserving Swift 3 невелик,оннемногоулучшился。

Смыслвтом, updatedAt 。 在ViewController ,请在ViewController添加一个уведомленобизменении。 Key-Value Observing ViewController Key-Value Observing 。 至少要在viewDidLoad() ViewController和какпоказанониже中使用。

Дляопределенияпутимыиспользуемвыражение# #keyPath 。 Ключевойпуть—этонечтоиное,какпоследовательностьсвойствобъекта。 Swift 3之前。 Благодарядобавлениювыражений#keyPath,компиляторможетпроверитьправильностьпутиключивововремяко。 Строковыелитералынеимеютэтогопреимущества,чточастоприводиткошибкам。

Еслипутьключасчитаетсядействительным,компиляторзаменяетегостроковымлитераломвовремяко。 Зачем? Key-Value Observing используетObjective Objective-C runtimeObjective-C ключиипутиключейпредставленыстроками。 Ипомните,что Key-Value Observing возможноиспользоватьтолькопотому,чтоSwiftиспользуетObjective Objective-C runtime

Обратитевнимание,что #keyPathaddObserver(_: forKeyPath: options: context :) ,относитсяктекущейобластииконтексту。 , #keyPath(configurationManager.configuration.updatedAt)#keyPath(СonfigurationManager.configuration.updatedAt)

options: addObserver(_: forKeyPath: options: context :) 。 Поумолчаниюиспользуетсяпустойнаборпараметров。 Списокопцийопределяет,какуюинформациюпредоставляетнаблюдатель,когдапроисходитизмененее。 Ноэтотакжеопределяет,когданаблюдателюнеобходимоуведомлятьобизменениях。

  • new :этотпараметргарантирует,чтословарьизмененийвключаетновоезначениенаблюдаемогосвойства。
  • old :этотпараметргарантирует,чтословарьизмененийсодержитстароезначениенаблюдаемогосвойства。
  • initial
  • previous :этовариант,которыйвыредкобудетеиспользовать。 ,тотпараметргарантирует,чтонаблюдательполучаетуведомлениедоипослеизменения。

context: ,этоболеепродвинутыйвариант,которыйВытакжебудетередкоиспользовать。 Онпозволяетпередаватьдополнительныеданныенаблюдателюприотправкеуведомления。

ViewController вакачест。 Каконможетреагироватьнаизменения? Просто。 ViewController使用ObservValue observValue(forKeyPath: of: change: context :) ,другойметод,определяемыйкорневымклассомNSObject。 Этотметодтакжеопределяетчетырепараметра

forKeyPath: является# #keyPath ,вызвавшийуведомление。

of: ссылканаобъект,которыйоннаблюдает。

change: словарьтипа [NSKeyValueChangeKey : Any]? 。 Этотсловарьможетсодержатьнесколькопарключ-значение。 Содержимоезависитотпараметров,переданныхaddObserver addObserver(_: forKeyPath: options: context :)

context: контекст,которыйбылпередан,когданаблюдательбылдобавленранее。

Key-Value Observing watchValue(forKeyPath: of: change: context :)用于watchValue(forKeyPath: of: change: context :) Этоможетстатьдовольногрязнымделом。 Однакопример,скоторыммыработаем,прост。

ДажееслипараметрforKeyPathимееттип String? ,мыможемиспользоватьвыражение#keyPathдлясравнения。 ,тогарантирует,чтокомпиляторвыполнитнеобходимуюпроверкувовремякомпиляции。 Еслимыобнаружим,чтозначениесвойства updatedAt更新在конфигурацииизменено,мыобновимзначениеметкидаты。 Мымоглибывытащитьзначениеизсловаряизменений。 Проблемавтом,чтозначениявсловареимеюттипAny。 通过ConfigurationManager更改。

Запуститеприложение,чтобыузнать,обновляетсялизначениеметкидаты,есливынажимаетекнопку Update Configuration

WTF? Ононеработает? Сейчасисправим。 dynamicdynamicdynamicdynamic 。 使用Key-Value Observing可以使用Objective-C runtimeDynamic Dispatch

Чтожепроисходитнаэтомпростомпримере? Компилятордостаточноумён,чтобывыяснить,какимобразомнужнополучитьдоступксвойству在updatedAt更新了ConfigurationDynamic Dispatch分配( Dynamic Dispatch ,可立即进行Dynamic Dispatch分配(четовововремявыполнения)。 Dynamic Dispatch分配…,键值观察。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。 О, Key-Value Observing Dynamic Dispatch分配。

Какмыможемэтоисправить? Легко。 Мыдобавимпрефикс dynamic updatedAt 。 Atтоскажеткомпилятору,更新了чтосвойство在Dynamic Dispatch分发的всегдадолжнобытьдоступно时。

Запуститеприложениеещëраз,чтобыубедиться,чтоэторешилопроблему。

Когдаприложениезапускается,以及UILabelневерно。 Мыхотим,чтобыоноотображалоактуальноезначениесвойства updatedAt更新在экземпляраклассаConfiguration,тоетьтекущуд。

addObserver (_: forKeyPath: options: context :) ,которыймыобсуждалиранее? 至少要使用viewDidLoad() ,какпоказанониже和изапуститеприложениеснова。

Несмотрянато,чтозначениесвойства updatedAt更新在экземпляракласса Configuration ещëнеизменилось,наблюдателееееввелед 在ViewController添加watchValue(forKeyPath: of: change: context :)

Key-Value Observing —управлениепамятью。 Наблюдателидолжныбытьявноудалены, #keyPath 。 Увасестьдваварианта。

  • removeObserver(_: forKeyPath:)
  • removeObserver(_: forKeyPath: context:)

,предполагаю,чтоэтиметодыненуждаютсявобъяснении。 Keyтопоказывает,键值Key-Value Observing API 。 Вамнужноудалитьнаблюдателядлякаждого# #keyPath 。 ЕслиВызабудетеэтосделать,выполучитеутечкупамятиили,чтоещëхуже,сбойпрограммы。

ПроблемыKey Key-Value ObservingFacebookKVOController —从Key-Value Observing намногопрощеибезопаснее到Ветабиблиотека,котораяделат。 ОAPIигарантируетбезопасностьпотоков。 Вамстоитсамимэтопроверить。

Весьпроектпримератут。