KVO против NSNotification против протокола/делегатов?

У меня есть некоторое представление о том, что использовать, когда, но точное использование мне все еще не ясно. Может кто-нибудь объяснить на примере?


person Ankit Srivastava    schedule 23.10.2011    source источник
comment
Попробуйте прочитать это, это действительно интересная статья в блоге на эту тему с точки зрения программиста. blog.shinetech.com/2011/06/14/< /а>   -  person Daniel    schedule 23.10.2011


Ответы (6)


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

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

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

Надеюсь, это поможет.

PS Это резюмирует, почему я думаю, что KVO не работает

person deanWombourne    schedule 23.10.2011
comment
Я знаю, что это старо, но я все еще хочу с этим не согласиться :) В этой статье есть отличные аргументы. почему KVO API не работает, но в нем также точно указано, что это все еще мощный инструмент. Есть много ситуаций, когда это может сэкономить много уродливого кода. Используйте его с оберткой, подобной той, которую он предоставил, если хотите, но используйте ее. - person Shinigami; 17.01.2014
comment
Используйте KVO, когда наблюдателям требуется немедленный ответ. И можно использовать NSNotifications, когда наблюдатели могут ждать цикла событий. - person MANN; 06.01.2015
comment
@MANN Я не думаю, что понимаю - уведомления не асинхронны, они также запускаются немедленно (хотя вы не получаете опции willChange, которые вы получаете с KVO) - person deanWombourne; 07.01.2015
comment
@deanWombourne Никогда не говорил, что NSNotifications не асинхронны. Это просто следующий цикл событий. Ссылка -- developer.apple.com/library /ios/documentation/General/ --› ...Вместо центрального объекта, рассылающего уведомления всем объектам, зарегистрированным в качестве наблюдателей, KVO-уведомления отправляются непосредственно объектам-наблюдателям при изменении значений свойств. - person MANN; 07.01.2015
comment
@Shinigami, не могли бы вы описать несколько простых хороших примеров для KVO? - person Honey; 25.05.2016
comment
KVO — хорошая идея, если вам нужно перенести код на Mac, а затем воспользоваться привязками. - person adib; 12.02.2017

Используйте делегат, когда существует отношение «главный/подчиненный» (делегат знает о классе, а класс знает о делегате), когда один класс находится выше в иерархии управления, и когда ясно, что не будет ситуаций, когда другие элементы (в основном пользовательский интерфейс) будут заинтересованы в том, чтобы узнать, что должен сказать класс.

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

КВО полезно слушать "без ведома класса", хотя конечно это не так, класс на котором применяется КВО менять не надо.

person jbat100    schedule 23.10.2011

Делегирование — это шаблон проектирования, который вы используете, когда хотите, чтобы какой-то другой объект изменил поведение отправителя. Пример: окна терминала избегают отображения любых строк или символов, обрезанных краями окна, потому что делегат окна терминала изменяет размер окна, чтобы гарантировать это.

Уведомление — это шаблон, который можно использовать, когда вам не нужен ответ. Пример: вы получаете уведомление о том, что система собирается перейти в спящий режим. Отправителю этого уведомления все равно, что вы с ним сделаете.

person NSResponder    schedule 23.10.2011

Даже если все три будут служить вашим потребностям в ситуации, делегирование по-прежнему будет предпочтительным вариантом:

  1. Возможность повторного использования.
  2. Самодокументированный. Изучив заголовочный файл класса, можно было бы сразу узнать, что/как происходит обмен данными.
person user523234    schedule 16.03.2013

На мой взгляд, KVO лучше из-за его преимуществ с нулевыми накладными расходами. Уведомления имеют накладные расходы, даже если вы их не используете/не наблюдаете. Чтобы улучшить это, вы можете использовать разные Центры уведомлений, но даже при этом будут некоторые накладные расходы (поправьте меня, если я ошибаюсь). KVO немного сложен, но он того стоит, когда вам нужно наблюдать за многими вещами.

person MANN    schedule 12.10.2012
comment
Сколько, с практической точки зрения, накладные расходы? - person Liron; 05.02.2013

Шаблон делегирования, NotificationCenter, KVO

Шаблон delegate — это шаблон проектирования, который может относиться к шаблону Structural Decorator OR Wrapper от GoF, который добавляет поведение и обязанности к объекту без изменения его кода. Вы можете переместить некоторую логику в другой вспомогательный класс или использовать его в качестве скелета. Это альтернатива наследованию. Технически он использует association[О программе]. Язык Kotlin поддерживает шаблон delegate на языковом уровне. Что касается iOS, обычно он используется для Loose coupling для связи между классами Class1 <-> Class2 без Retain cycle[О программе] где SomeClass1 -> SomeClass2 и SomeClass2 weak-> SomeClass1

protocol SomeProtocol {
    func foo()
}

class SomeClass1: SomeProtocol {
    let someClass2 = SomeClass2()

    init() {
        someClass2.delegate = self
    }
    
    func foo() {
        print("foo is called")
    }
}

class SomeClass2 {
    
    weak var delegate: SomeProtocol?
    
    func onButtonTap() {
        delegate?.foo()
    }
}

NotificationCenter or NSNotificationCenter(Objective-C) (не удаленные (Push) или локальные уведомления) является разновидностью publish/subscribe event bus. У вас есть NotificationCenter одноэлементный объект, который является единственной точкой для отправки или получения события. Вы можете использовать его для отправки событий через все приложение, и любой может прервать его. Такая система быстро развивается, но тяжело поддерживается. Это тоже своего рода Loose coupling система.

Вы можете использовать следующий API NotificationCenter:

post(name: object: userInfo:)
addObserver(_ observer: selector: name: object:)
removeObserver(_ observer: selector: object:)

KVO — Наблюдение за ключом-значением. Наблюдение за изменениями значения поддерживаемого свойства Objective-C. Вы можете использовать его, когда вам нужно знать о каких-то изменениях на объекте без какого-либо запроса.

Objective-C -@property[О программе], который использует willChangeValueForKey и didChangeValueForKey за KVO

*Примечания

  • Если вы переопределяете willChangeValueForKey, didChangeValueForKey, observeValueForKeyPath не срабатывает
  • Если вы используете установщик iVar[About], вы несете ответственность за вызов willChangeValueForKey, didChangeValueForKey
#import "SomeClass.h"

@interface SomeClass()
@property (nonatomic, strong) NSString *someVariable;
@end

@implementation SomeClass
- (void) foo 
{    
    [self addObserver: self forKeyPath: @"someVariable" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context: nil];
    
    self.someVariable = @"set someVariable";
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"someVariable"]) {
        NSLog(@"%@", change);
    }
}

@end

SwiftNSObject и @objc dynamic[О программе]

class SomeClass1 : NSObject {
    @objc dynamic var v = 0
}

class SomeClass2 {
    var kvoToken: NSKeyValueObservation?
    
    func subscribe(someClass1: SomeClass1) {
        kvoToken = someClass1.observe(\.v, options: .new) { (object, change) in
            guard let value = change.newValue else { return }
            print("New value: \(value)")
        }
    }
    
    deinit {
        kvoToken?.invalidate()
    }
}

or

public class SomeClass: NSObject 
    public override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {

    }
}

func foo() {
    someClass1.addObserver(self, forKeyPath: "v", options: .new, context: nil)
}

[Objective-C KVC против KVO]
[Swift KVC]

person yoAlex5    schedule 12.02.2021