swift:监听 “struct variable”-change 事件?

swift: Listen for "struct variable"-change event?

提问人:Jonas0000 提问时间:1/10/2018 最后编辑:rmaddyJonas0000 更新时间:2/11/2018 访问量:2130

问:

我有一个小问题:

如何侦听另一个(“不可编辑!!”)类中声明的更改?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()


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

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

iOS Swift 结构 实例

评论

1赞 Rob Napier 1/10/2018
正如你所写的那样,没有真正实用的答案。如果实际代码的细节不同,可能会有一个答案,但正如所写的那样,没有很好的方法来观察该属性。“如果实际代码的细节不同”的一个例子是 是否是 的子类(以及是否是唯一改变的东西)。如果这是真的,那么 swizzling 将使这成为可能(swizzling 在生产代码中非常危险,但如果你有源代码,它会更安全)。FixedClassNSObjectupdateVarinstance.abcupdateVar
0赞 Jonas0000 1/10/2018
听起来还不错。但是 tbh - 我不能 100% 理解你的想法。您愿意与我们分享一些代码片段吗?@Rob
0赞 Rob Napier 1/10/2018
是子类吗?是否唯一修改此值的内容(因此您真的想知道何时调用而不是何时更改值)?FixedClassNSObjectupdateVarupdateVar

答:

-1赞 creeperspeak 1/10/2018 #1

一种方法是使用 NotificationCenter 广播更改,并让您监听该更改并对其做出反应。您的实现可能如下所示: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())")
    }
  }
}

评论

0赞 Rob Napier 1/10/2018
这修改了 ,这是问题所禁止的。FixedClass
0赞 creeperspeak 1/10/2018
@RobNapier 你是对的——我很抱歉。我以为他的意思是那门课是,但我认为我读得不够仔细。无论哪种方式,我都认为不可能在不以某种方式修改的情况下完成要求的事情。private
0赞 Jonas0000 1/10/2018
谢谢你的回答 爬行者说话 - 但你知道..这与我的问题并不匹配。然而。如果我将结构作为公共值获得怎么办?所以我可以通过使用'let thevar = MyObject.abc'从每个类中获取?现在可能吗?MyObject
0赞 creeperspeak 1/10/2018
据我所知,如果不向 FixedClass 添加至少 1 行,您将无法完成此操作,但请检查其他注释。
1赞 Upholder Of Truth 1/10/2018 #2

这将完全取决于如何定义“真正的”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 的属性,然后调用委托方法。在某些时候,您必须将 observing 类指定为子类的委托(我在 init 方法中作为测试做到了这一点)。

因此,这样做我可以观察结构何时更改,但我没有触及 FixedClass。

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

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

1赞 Rob 1/10/2018 #3

有几件事:

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

  2. 如果您无法编辑该类,在某些狭隘的情况下,理论上可以对其进行子类化并添加所需的任何观察系统。这显然只有在手动实例化时才有效,这取决于实现方式,但在某些狭隘的情况下,您可以通过子类化来实现所需的内容。FixedClassFixedClass

    你问:

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

    当然,请考虑您的: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")
    }
    

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

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