Swift中的观察者模式

Swift中的观察者模式

问题描述:

我想实现一个观察者模式,但是我在Swift(2.0)中找不到合适的编程语言结构。主要问题是:Swift中的观察者模式

  1. extension不允许存储的属性。
  2. 在类中我们可以添加存储的属性,但是我们不能强制子类重写它的一些继承方法。

这就是我想要的:

{class|protocol|extension|whathaveyou} Sensor { 
    var observers = Array<Any>() // This is not possible in protocol and extensions 
    // The following is does not work in classes 
    func switchOn() 
    func switchOff() 
    var isRunning : Bool { 
     get 
    } 
} 

class LightSensor : Sensor { 
    //... 
    override func switchOn() { 
     // turn the sensor on 
    } 
} 

// In the class C, implementing the protocol 'ObserverProtocol' 

var lightSensor = LightSensor() 
lightSensor.switchOn() 
lightSensor.registerObserver(self) // This is what I want 

这里来什么是可能的,据我所知:

class Sensor { 
    private var observers = Array<Observer>() 

    func registerObserver(observer:ObserverDelegate) { 
     observers.append(observer) 
    } 
} 

protocol SensorProtocol { 
    func switchOn() 
    func switchOff() 
    var isRunning : Bool { 
     get 
    } 
} 

class LightSensor : Sensor, SensorProtocol { 
    func switchOn() { 
     // 
    } 
    func switchOff() { 
     // 
    } 

    var isRunning : Bool { 
     get { 
      return // whatever 
     } 
    } 
} 

但是,这是不是很方便,因为这两个SensorSensorProtocol应该来并且是子类LightSensor必须满足的两个要求。

任何想法?

+0

这可能是不可能的,因为你不能创建扩展权瓦尔?就我而言,这适用于普通班级 –

+0

是的,但正如我写的,在班级中,我无法执行需要实施的方法! –

+0

我更新了演示代码,以明确我想要什么,什么是不可能的。 –

协议是跨多个(可能非常不同的)其他对象共享的一组抽象需求。因此,将数据存储在协议中是不合逻辑的。这就像全球的国家。我可以看到你想要定义观察者如何存储的规范。这也可以让'你'从观察者身上移除'他人',这对观察者的存储方式是非常有限制的。

因此,你的协议应该公开方法来添加和删除“你自己”作为观察者。那么执行协议的对象有责任决定观察者如何以及在哪里存储并实施添加和删除。


您可以创建一个结构与协议的工作,是这样的:

protocol Observer: class { 
    func notify(target: Any) 
} 

protocol Observable { 
    mutating func addObserver(observer: Observer) 
    mutating func removeObserver(observer: Observer) 
} 

struct Observation: Observable { 
    var observers = [Observer]() 

    mutating func addObserver(observer: Observer) { 
     print("adding") 
     observers.append(observer) 
    } 
    mutating func removeObserver(observer: Observer) { 
     print("removing") 
     for i in observers.indices { 
      if observers[i] === observer { 
       observers.removeAtIndex(i) 
       break 
      } 
     } 
    } 
    func notify(target: Any) { 
     print("notifying") 
     for observer in observers { 
      observer.notify(target) 
     } 
    } 
} 

struct ATarget: Observable { 
    var observation = Observation() 

    mutating func addObserver(observer: Observer) { 
     observation.addObserver(observer) 
    } 
    mutating func removeObserver(observer: Observer) { 
     observation.removeObserver(observer) 
    } 

    func notifyObservers() { 
     observation.notify(self) 
    } 
} 

class AnObserver: Observer { 
    func notify(target: Any) { 
     print("notified!") 
    } 
} 

let myObserver = AnObserver() 
var myTarget: Observable = ATarget() 
myTarget.addObserver(myObserver) 

if let myTarget = myTarget as? ATarget { 
    myTarget.notifyObservers() 
} 
+0

我完全同意你对协议的定义。但是,我使用协议只是因为没有强制子类重写方法的选项。这就是我真正想要的... –

+0

你应该为没有实现的协议功能发生构建错误 – Wain

+0

是的,但是我不能在协议中添加存储的属性,比如数组,我需要观察者模式。 –

好了,你肯定能战胜没有在扩展存储性能的限制。 也许你可以用一种扩展来补充其中一种解决方案,这样可以避免在每个子类/协议实现中创建观察者列表。

尽管扩展不能存储属性,但实际上可以通过使用Objective-C运行时获取它们。假设你有你的传感器(BaseSensor)和观察员协议(SensorObserver)基类:

import Foundation 
import ObjectiveC 

private var MyObserverListKey: UInt8 = 0 

extension BaseSensor { 
    var observers:[SensorObserver] { 
    get { 
     if let observers = objc_getAssociatedObject(self, &MyObserverListKey) as? [SensorObserver] { 
     return observers 
     } 
     else { 
     var observers = [SensorObserver]() 
     objc_setAssociatedObject(self, &MyObserverListKey, observers, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) 
     return observers 
     } 
    } 
    set(value) { 
     objc_setAssociatedObject(self, &MyObserverListKey, observers, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC)) 
    } 
    } 
} 

需要明确的是,即使你需要BaseSensor和所有传感器继承它,才能有此属性,BaseSensor实际上不会实现Sensor协议。 这是一个有点怪异,但我认为这将满足您的需求:

class BaseSensor { 
} 

protocol Sensor { 
    func switchOn() 
} 

class LightSensor: BaseSensor, Sensor { 
    func switchOn() { 
    // whatever 
    } 
} 

与SWIFT 2.0,这将是简单得多,因为你可以使用协议扩展,所以你可以简单地这样做:

protocol Sensor { 
    func switchOn() 
} 

extension Sensor { 
    // Here the code from the previous implementation of the extension of BaseSensor 
} 

class LightSensor : Sensor { 
    func switchOn() { 
    // whatever 
    } 
} 

方式更好。

+0

感谢您的贡献,但回到Objective-C?苹果,认真吗? :-) –

这是我在夫特3

import UIKit 

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     var objectToObserve = ObjectToObserve() 

     let observer = Observer() 
     let observer1 = Observer() 

     objectToObserve.add(observer: observer, notifyOnRegister: true) 
     objectToObserve.add(observer: observer1, notifyOnRegister: true) 
    } 
} 

// 
// MARK: Protocol 
// 
protocol Observing: class { 
    func doSomething() 
    func doSomethingClosure(completion:() -> Void) 
} 

protocol Observable { 

} 

extension Observable { 

    private var observers: [Observing] { 
     get { 
      return [Observing]() 
     } 
     set { 
      //Do nothing 
     } 
    } 

    mutating func add(observer: Observing, notifyOnRegister: Bool) { 
     if !observers.contains(where: { $0 === observer }) { 
      observers.append(observer) 

      if notifyOnRegister { 
       observer.doSomething() 
       observer.doSomethingClosure(completion: { 
        print("Completion") 
       }) 
      } 
     } 
    } 

    mutating func remove(observer: Observing) { 
     observers = observers.filter({ $0 !== observer }) 
    } 
} 

// 
// MARK: Observing 
// 
class ObjectToObserve: Observable { 

    init() { 
     print("Init ObjectToObserve") 
    } 
} 

class Observer: Observing { 

    init() { 
     print("Init Observer") 
    } 

    func doSomething() { 
     print("Do something") 
    } 

    func doSomethingClosure(completion:() -> Void) { 
     print("Do something Closure") 
     completion() 
    } 
} 
+0

我相信'private var observers:[Observing]'有一个错误,getter将总是返回一个空数组:] – pxpgraphics

溶液上方错误地全部回答使用数组用于保持观察员,其可产生保留,因为强引用的周期。

此外,一般情况下,您可能不希望允许相同的观察者注册两次。

提出的解决方案也不是通用或缺乏类型安全。我在这里引用我的博客文章呈现在SWIFTY方式完整的解决方案:

https://www.behindmedia.com/2017/12/23/implementing-the-observer-pattern-in-swift/