虽然我有一些想法可以使用,但确切用法仍然不清楚。有人能解释一下......?感谢。
答案 0 :(得分:38)
如果您只想与一个对象交谈,请使用委托。例如,tableView有一个委托 - 只有一个对象负责处理它。
如果您想告诉所有人发生了某些事情,请使用通知。例如,在内存不足的情况下,会发送通知,告知您的应用程序存在内存警告。由于您应用中的大量对象可能希望降低其内存使用量,因此这是一个通知。
我认为KVO根本不是一个好主意,并且尽量不使用它但是,如果你想知道一个属性是否已经改变,你可以听取改变。
希望有所帮助。
答案 1 :(得分:13)
当存在“主/从”关系时(委托知道类和类知道委托),使用委托,一个类在控制层次结构的上方,当很明显不存在时其他元素(主要是UI)将有兴趣知道类必须说什么的情况。当班级不知道谁听谁以及他们有多少时,使用通知,任何人和任何号码都可以注册通知。 KVO对于“没有课堂知道”是有用的,虽然当然不是这种情况,但是应用KVO的课程不需要改变。
答案 2 :(得分:2)
委派是一种设计模式,当您希望其他对象修改发件人的行为时,可以使用该模式。示例:终端窗口避免显示由窗口边缘剪切的任何行或字符,因为终端窗口的委托会改变窗口的大小以确保这一点。
通知是您不需要回复时使用的模式。示例:您会收到系统即将进入睡眠状态的通知。该通知的发件人并不关心您对此采取的措施。
答案 3 :(得分:2)
即使所有三个都满足您的需求,代表仍然是一个更喜欢的选择:
答案 4 :(得分:1)
在我看来,KVO更好,因为它具有零开销优势。 即使您没有使用/观察它们,通知也会有开销。为了改善它你可以使用不同的NotificationCenters,但即使有一些开销将在那里(纠正我,如果我错了)。 KVO有点复杂,但是当你需要观察很多东西时它是值得的。
答案 5 :(得分:0)
委托模式、通知中心、KVO
delegate
模式是一种设计模式,它可以与 GoF 的 Structural Decorator OR Wrapper 模式相关联,它可以在不更改对象代码的情况下向对象添加行为和责任。你可以将一些逻辑移到另一个辅助类中或将其用作骨架。它是继承的替代方案。从技术上讲,它使用 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:)
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)
}