我想实现一个观察者模式,但是我没有在Swift(也是2.0)中找到合适的编程语言结构。主要问题是:
protocol
和extension
不允许存储的属性。 这就是我想要的:
{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
}
}
}
但这不是很方便,因为Sensor
和SensorProtocol
都应该齐头并进,并且都是子类LightSensor
必须满足的要求。
有什么想法吗?
答案 0 :(得分:5)
协议是在许多(可能非常不同的)其他对象之间共享的一组抽象需求。因此,将数据存储在协议中是不合逻辑的。这就像全球国家。我可以看到你想要定义观察者如何存储的规范。这也可以让你“#”;删除其他人&#39;作为一个观察者,它对观察者的存储方式有着非常严格的限制。
因此,您的协议应该公开添加和删除自己的方法。作为观察者。然后,实施协议的对象有责任决定观察者的存储方式和位置,并实施添加和删除。
您可以创建一个结构来使用您的协议,例如:
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()
}
答案 1 :(得分:1)
这是我在Swift 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()
}
}
答案 2 :(得分:0)
嗯,你当然可以克服在扩展上没有存储属性的限制。 也许这样你可以用一个扩展来补充一个提议的解决方案,这个扩展可以帮助你避免在每个子类/协议实现中创建观察者列表。
虽然扩展不能有存储属性,但实际上可以通过使用Objective-C Runtime来获取它们。假设您有传感器的基类(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也不会实际实现传感器协议。 这有点奇怪,但我认为它符合您的需求:
class BaseSensor {
}
protocol Sensor {
func switchOn()
}
class LightSensor: BaseSensor, Sensor {
func switchOn() {
// whatever
}
}
使用Swift 2.0,这会更简单,因为你可以使用Protocol Extensions,所以你可以这样做:
protocol Sensor {
func switchOn()
}
extension Sensor {
// Here the code from the previous implementation of the extension of BaseSensor
}
class LightSensor : Sensor {
func switchOn() {
// whatever
}
}
更好的方式。
答案 3 :(得分:0)
上面的所有答案都错误地使用数组来保留观察者,由于强引用,这可能会创建保留周期。
通常,您可能不希望允许同一个观察者自己注册两次。
所提出的解决方案也不是通用的或缺乏类型安全性。我在这里引用我的博客文章,以一种Swifty的方式呈现完整的解决方案:
https://www.behindmedia.com/2017/12/23/implementing-the-observer-pattern-in-swift/