【发布时间】:2011-12-13 11:18:02
【问题描述】:
我对何时使用哪个有一些想法,但我仍然不清楚确切的用法。有人可以举例说明吗?
【问题讨论】:
-
尝试阅读这篇文章,这是一篇非常有趣的博客文章,从编码人员的角度来看该主题。 blog.shinetech.com/2011/06/14/…
标签: iphone ios protocols key-value-observing nsnotifications
我对何时使用哪个有一些想法,但我仍然不清楚确切的用法。有人可以举例说明吗?
【问题讨论】:
标签: iphone ios protocols key-value-observing nsnotifications
如果您只想与一个对象交谈,请使用委托。例如,一个 tableView 有一个委托 - 只有一个对象应该负责处理它。
如果您想告诉所有人发生了什么事,请使用通知。例如,在内存不足的情况下,会发送一条通知,告诉您的应用程序存在内存警告。因为您的应用程序中的许多对象可能希望降低其内存使用量,所以这是一个通知。
我认为 KVO 根本不是一个好主意,尽量不要使用它,但是,如果你想知道某个属性是否发生了变化,你可以监听变化。
希望对您有所帮助。
【讨论】:
当存在“主/从”关系时使用委托(委托知道类,类知道委托),一个类在控制层次结构中更高,并且很明显不会有其他元素(主要是 UI)有兴趣知道类要说什么的情况。
当班级不想知道谁在听以及他们有多少人不感兴趣时,使用通知,任何人和任何号码都可以注册通知。
KVO 在“不知道类”的情况下听很有用,虽然当然不是这样,应用 KVO 的类不需要更改。
【讨论】:
委托是一种设计模式,当您希望其他对象修改发送者的行为时,您可以使用该模式。示例:终端窗口避免显示任何被窗口边缘剪裁的行或字符,因为终端窗口的委托会更改窗口的大小以确保这一点。
通知是一种在您不需要响应时使用的模式。示例:您收到系统即将进入睡眠状态的通知。该通知的发送者并不关心您对此做了什么。
【讨论】:
即使在某种情况下这三个都可以满足您的需求,委托仍然是首选:
【讨论】:
在我看来,KVO 更好,因为它具有零开销的优势。 即使您没有使用/观察通知,通知也会产生开销。为了改善这一点,您可以使用不同的通知中心,但即使这样也会有一些开销(如果我错了,请纠正我)。 KVO 有点复杂,但当您必须观察大量内容时,它是值得的。
【讨论】:
委托模式、通知中心、KVO
委托
delegate 模式是一种与结构(GoF 的装饰器或包装器模式)相关的设计模式,它在不更改代码的情况下向对象添加行为和职责。你可以将一些逻辑移动到另一个辅助类中或将其用作骨架。它是继承的替代方案。从技术上讲,它使用association[About]。 Kotlin 语言在语言层支持delegate 模式。至于iOS,它通常用于Loose coupling 用于类之间的通信Class1 <-> Class2 没有Retain cycle[About] 其中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)(不是远程(推送)或本地通知)是publish/subscribe event bus 的一种。您有 NotificationCenter 单例对象,它是任何人发送或接收事件的单点。您可以使用它通过所有应用程序发送事件,任何人都可以中断它。这样的系统开发速度快,但支持难度大。也是Loose coupling系统的一种。
您可以使用 NotificationCenter 的下一个 API:
post(name: object: userInfo:)
addObserver(_ observer: selector: name: object:)
removeObserver(_ observer: selector: object:)
例如系统显示,隐藏键盘
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(MyViewController.keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
@objc func keyboardWillShow(_ notification:Notification) {
}
@objc func keyboardWillHide(_ notification:Notification) {
}
KVO
KVO - 键值观察。观察 Objective-C 支持的属性值的变化。当您需要了解对象的某些更改而无需任何请求时,您可以使用它
Objective-C -@property[About] 使用willChangeValueForKey 和didChangeValueForKey 表示KVO
*备注
willChangeValueForKey、didChangeValueForKey,则不会触发 observeValueForKeyPath
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
Swift - NSObject 和 @objc dynamic[About]
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()
}
}
或
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)
}
【讨论】: