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 runtime
。 Objective-C
ключиипутиключейпредставленыстроками。 Ипомните,что Key-Value Observing
возможноиспользоватьтолькопотому,чтоSwiftиспользуетObjective Objective-C runtime
。
Обратитевнимание,что #keyPath
, addObserver(_: 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? Ононеработает? Сейчасисправим。 dynamic
, dynamic
, dynamic
, dynamic
。 使用Key-Value Observing
可以使用Objective-C runtime
和Dynamic Dispatch
。
Чтожепроисходитнаэтомпростомпримере? Компилятордостаточноумён,чтобывыяснить,какимобразомнужнополучитьдоступксвойству在updatedAt
更新了Configuration
。 Dynamic 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 Observing
由Facebook
。 KVOController
—从Key-Value Observing
намногопрощеибезопаснее到Ветабиблиотека,котораяделат。 ОAPIигарантируетбезопасностьпотоков。 Вамстоитсамимэтопроверить。
Весьпроектпримератут。