斯威夫特:听"struct variable"变化事件?



我遇到了一个小问题:

怎么可能侦听在另一个(">不可编辑!!")类中声明的struct-instance variable的变化?


添加了一些小的代码片段来澄清我的想法。

说明

  • FixedClass是一个不可编辑的类:我不想更改/我无法更改"FixedClass"的任何代码

  • EditableClass可以编辑 - 我相信你会看代码(^_^)/得到它


代码

let fixedClass: FixedClass = FixedClass()
class FixedClass {
struct MyObject {
var abc = 0
}
var instance = MyObject()
public init() { Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.updateVar), userInfo: nil,  repeats: true) }
@objc func updateVar() {
instance.abc+=1
}
func getVar() -> Int {
return instance.abc
}
}

let editableClass: EditableClass = EditableClass()
class EditableClass {
public init() { }
func listenForChange() {
// listen for change event of FixedClass.getVar()
print("Variable: (fixedClass.getVar())")
}
}


通话方式:editableClass.listenForChange()


总而言之,我想听听FixedClass.getVar()结果的变化 - 最好避免使用loopstimers.然而,最重要的是至少让它工作。

任何帮助将不胜感激,谢谢!

这将完全取决于如何定义"真正的"FixedClass。 即它是NSObject的子类,它是ObjectiveC类,你想要观察的属性是如何定义的。

就您的实际示例而言,您可以通过像这样进行子类化来实现:

var newFixedClass: NewFixedClass = NewFixedClass()
var editableClass: EditableClass = EditableClass()
protocol NewFixedClassProtocol: class {
func changed(newFixedClass: NewFixedClass)
}
class NewFixedClass: FixedClass {
public weak var delegate: NewFixedClassProtocol?
override var instance: FixedClass.MyObject {
didSet {
self.delegate?.changed(newFixedClass: self)
}
}
}
class EditableClass: NewFixedClassProtocol {
public init() {
newFixedClass.delegate = self
}
func changed(newFixedClass: NewFixedClass) {
print ("Value = (newFixedClass.instance.abc)")
}
}

因此,您基本上创建了一个执行观察的类支持的协议,创建 FixedClass 的一个子类,该子类具有协议类型的委托,并使用 didSet 观察器覆盖要观察的 FixedClass 的属性,然后调用委托方法。 在某些时候,您必须将观察类指定为子类的委托(我在 init 方法中作为测试做到了这一点)。

所以这样做我可以观察结构何时发生变化,但我还没有接触 FixedClass。

但请注意,此方法在很大程度上依赖于对原始 FixedClass 的了解,因此可能不适用于您的"现实世界"情况。

(另外,我无法让它与类的全局定义实例一起使用,并且必须在我的初始视图控制器中设置它们,但这可能与我的测试方式有关,并且不会更改所涉及的方法)

有几件事:

  1. 如果原始类是 Objective-C 或以其他方式参与 KVO(例如 Swiftdynamic子类的属性NSObject等),那么您可以观察到变化。但这是一个相当狭窄的用例。但这是使一个人的属性可以被其他对象观察到的一般模式。有关更多信息,请参阅《键值观察编程指南》。

  2. 如果你不能编辑类,在某些狭窄的情况下,理论上你可以对它进行子类化,并添加你想要的任何观察系统。这显然只有在您手动实例化FixedClass时才有效,并且取决于FixedClass的实现方式,但在某些狭窄的情况下,您可以通过子类化实现所需的内容。

    你问:

    您愿意与我们分享一些代码片段吗?

    当然,考虑一下你的FixedClass

    class FixedClass {
    struct MyObject {
    var abc = 0
    }
    var instance = MyObject()
    public init() { Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.updateVar), userInfo: nil,  repeats: true) }
    @objc func updateVar() {
    instance.abc+=1
    }
    func getVar() -> Int {
    return instance.abc
    }
    }
    

    然后,您可以定义一个子类:

    class FixedClassSubclass: FixedClass {
    static let changeNotification = NSNotification.Name(rawValue: Bundle.main.bundleIdentifier! + ".FixedClassSubclassNotification")
    override func updateVar() {
    super.updateVar()
    NotificationCenter.default.post(name: FixedClassSubclass.changeNotification, object: self)
    }
    }
    

    然后你可以做:

    let fixed = FixedClassSubclass()
    

    NotificationCenter.default.addObserver(forName: FixedClassSubclass.changeNotification, object: nil, queue: nil) { _ in
    print("changed")
    }
    

    您可以使用所需的任何通知过程。NotificationCenter.KVN.委托协议模式。无论什么。这方面的细节将完全根据FixedClass的细节而有所不同,您为我们提供了一个人为的例子,在许多情况下不太可能扩展。

我必须承认,对于试图挂钩到不可编辑类的内部实现细节的想法,我有一些普遍的疑虑。我们通常努力使用仅依赖于已发布的、受支持的接口的松散耦合对象。这种努力违反了这两个目标。但我假设你有一些很好的理由去做你试图做的事情。

执行此操作的一种方法是使用通知中心广播更改,并让您的EditableClass侦听该更改并对其进行响应。 您的实现可能如下所示:

class FixedClass { //Class names should start with capital letters
struct MyObject { //Struct names should also start with capital letters
var abc = 0
}
var instance = myObject()
public init() { Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.updateVar), userInfo: nil,  repeats: true) }
@objc func updateVar() {
instance.abc+=1
//Broadcast the change, and pass this FixedClass instance
NotificationCenter.default.post(name: Notification.Name("fixedClassChanged"), object: self)
}
func getVar() -> Int {
return instance.abc
}
}

然后,您可以在EditableClass中对此广播做出如下反应:

class EditableClass {
public init() { }
func listenForChange() {
//Observe same notification being broadcast by the other class
NotificationCenter.default.addObserver(self, selector: #selector(processChange(_:)), name: Notification.Name("fixedClassChanged"), object: nil)
}
@objc func processChange(_ sender: Notification) {
//When the notification comes in, check to see if the object passed in was a FixedClass, and if so process whatever needs to be processed
if let fixed = sender.object as? FixedClass {
print("Class changed to (fixed.getVar())")
}
}
}

最新更新