Swift中的观察者模式
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Swift中的观察者模式相关的知识,希望对你有一定的参考价值。
我想实现一个观察者模式,但我没有在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
子类必须满足的要求。
有任何想法吗?
协议是在许多(可能非常不同的)其他对象之间共享的一组抽象需求。因此,将数据存储在协议中是不合逻辑的。这就像全球国家。我可以看到你想要定义观察者如何存储的规范。这也将允许'你'删除'别人'作为观察者,并且对观察者的存储方式有非常严格的限制。
因此,您的协议应该公开添加和删除“您自己”作为观察者的方法。然后,实现协议的对象负责决定观察者的存储方式和位置,并实现添加和删除。
您可以创建一个结构来使用您的协议,例如:
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()
}
这是我在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()
}
}
好吧,你当然可以克服在扩展上没有存储属性的限制。也许这样,您可以使用扩展来补充提议的解决方案之一,该扩展可帮助您避免在每个子类/协议实现中创建观察者列表。
虽然扩展不能存储属性,但实际上可以使用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
}
}
方式更好。
上面的所有答案都错误地使用数组来保留观察者,由于强引用,这可能会创建保留周期。
通常,您可能不希望允许同一个观察者自己注册两次。
所提出的解决方案也不是通用的或缺乏类型安全性。我在这里引用我的博客文章,以一种Swifty方式呈现完整的解决方案:
https://www.behindmedia.com/2017/12/23/implementing-the-observer-pattern-in-swift/
以上是关于Swift中的观察者模式的主要内容,如果未能解决你的问题,请参考以下文章
设计模式 行为型模式 -- 观察者模式(发布-订阅(Publish/Subscribe)模式)
是否应该重写 deinit 以删除 Swift 中的观察者?
Java设计模式补充:回调模式事件监听器模式观察者模式(转)