ios KVO vs NSNotification vs protocol/delegates?

pvcm50d1  于 2023-08-08  发布在  iOS
关注(0)|答案(6)|浏览(107)

我知道什么时候该用哪个,但确切的用法我还是不清楚。有人能举例说明吗?

z9smfwbn

z9smfwbn1#

如果只想与一个对象对话,请使用委托。例如,一个tableView有一个委托-只有一个对象应该负责处理它。
如果你想告诉所有人发生了什么事,就使用通知。例如,在内存不足的情况下,系统会发送通知,告知您的应用出现内存警告。因为应用中的许多对象可能希望降低其内存使用量,所以它是一个通知。
我不认为KVO是一个好主意,尽量不要使用它,但是,如果你想知道一个属性是否发生了变化,你可以监听它的变化。
希望能帮上忙。
PS This sums up why I think KVO is broken

mbskvtky

mbskvtky2#

当存在“主/从”关系(委托知道类,类知道委托)时,使用委托,其中一个类在控件层次结构中更高,并且当很明显不会有其他元素(主要是UI)对知道类必须说什么感兴趣的情况时。
当班级不想知道谁在听以及有多少人在听时,使用通知,任何人和任何号码都可以注册通知。
KVO在“不被全班知道”的情况下听是有用的,当然情况并非如此,应用KVO的班级不需要改变。

3pmvbmvn

3pmvbmvn3#

委托是一种设计模式,当您希望其他对象修改发送方的行为时可以使用它。例如:终端窗口避免显示任何被窗口边缘剪裁的行或字符,因为终端窗口的代理会更改窗口的大小以确保这一点。
通知是在不需要响应时使用的一种模式。示例:您收到系统即将进入睡眠状态的通知。通知的发送者并不关心你对它做了什么。

6psbrbz9

6psbrbz94#

即使这三种方式都能满足你的需要,委派仍然是一个更好的选择:
1.可重复使用性。
1.自我记录。通过检查类的头文件,可以立即识别出交换的数据是什么/如何发生的。

ryhaxcpt

ryhaxcpt5#

iOS代理模式、通知中心、KVO
代理人

delegate模式是一种设计模式,它可以与Structural(GoF的Decorator或Wrapper模式)相关,它在不改变代码的情况下向对象添加行为和责任。Yo可以将一些逻辑移到另一个helper类中,或者将其用作 backbone 。它是继承的替代方案。从技术上讲,它使用的是associationAbout(https://stackoverflow.com/a/65967271/4770877)。Kotlin语言在语言层上支持delegate模式。对于iOS,通常用于Loose coupling,用于类Class1 <-> Class2之间的通信,而不包括Retain cycleAbout(https://stackoverflow.com/a/61020491/4770877),其中SomeClass1 -> SomeClass2SomeClass2 weak-> SomeClass1

protocol SomeProtocol: AnyObject {
    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 singleton对象,它是任何人都可以发送或接收事件的单个点。您可以使用它通过all应用程序发送事件,任何人都可以中断它。这种系统开发速度快,但支持难度大。它也是一种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-键值观察。正在观察Objective-C支持的属性值的更改。当您需要了解对象上的某些更改时,可以使用它,而无需任何请求

目标-C-@propertyAbout(https://stackoverflow.com/a/66233088/4770877),它使用willChangeValueForKeydidChangeValueForKey来表示KVO

  • 注意事项
  • 如果覆盖willChangeValueForKeydidChangeValueForKey,则不会触发observeValueForKeyPath
  • 如果您使用iVar About(https://stackoverflow.com/a/66233088/4770877)设置器,则您负责调用willChangeValueForKeydidChangeValueForKey
#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

斯威夫特-NSObject@objc dynamicAbout(https://stackoverflow.com/a/60937714/4770877)

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)
}


Objective-C KVC vs KVO(https://stackoverflow.com/a/67622702/4770877)的
Swift KVC(https://stackoverflow.com/a/66163865/4770877)

u0njafvf

u0njafvf6#

在我看来,KVO更好,因为它的零开销的优势。即使你没有使用/观察它们,通知也会有开销。为了改善这一点,你可以使用不同的通知中心,但即使这样,一些开销将在那里(纠正我,如果我错了)。KVO有点复杂,但当你必须观察很多东西时,它是值得的。

相关问题