Skip to content

Instantly share code, notes, and snippets.

@codelynx
Last active November 7, 2016 14:13
Show Gist options
  • Select an option

  • Save codelynx/c7829b2b71102e09e52ff485a6fa3c10 to your computer and use it in GitHub Desktop.

Select an option

Save codelynx/c7829b2b71102e09e52ff485a6fa3c10 to your computer and use it in GitHub Desktop.
Lightweight utility code to implement change propagation mechanism from observable objects to observer objects.
// ZObservable
// ZKit
//
// The MIT License (MIT)
//
// Copyright (c) 2016 Electricwoods LLC, Kaz Yoshikawa.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
public protocol ZObserver: ZObservable {
func observableDidChange(_ observable: ZObservable)
func addObservable(_ observable: ZObservable)
}
extension ZObserver {
public func addObservable(_ observable: ZObservable) {
ZObservatory.shared.add(observer: self, observable: observable)
}
public func addObservables(_ observables: [ZObservable]) {
for observable in observables {
ZObservatory.shared.add(observer: self, observable: observable)
}
}
public func removeObservable(_ observable: ZObservable) {
ZObservatory.shared.remove(observer: self, observable: observable)
}
}
public protocol ZObservable: AnyObject {
func observableDidChange()
func addObserver(_ observer: ZObserver)
}
public extension ZObservable {
func observableDidChange() {
ZObservatory.observableDidChange(self)
}
func addObserver(_ observer: ZObserver) {
ZObservatory.shared.add(observer: observer, observable: self)
}
func removeObserver(_ observer: ZObserver) {
ZObservatory.shared.remove(observer: observer, observable: self)
}
}
public class ZObservatory {
fileprivate var table = NSMapTable<AnyObject, ZWeakSet<AnyObject>>.weakToStrongObjects()
public static let shared = ZObservatory()
private let _lock = NSLock()
private init() {
}
public func observableDidChange(_ observable: ZObservable) {
if let objectSet = self.table.object(forKey: observable) {
for pointerObject in objectSet.objects {
if let observer = pointerObject as? ZObserver {
observer.observableDidChange(observable)
}
}
}
}
public class func observableDidChange(_ observable: ZObservable) {
self.shared.observableDidChange(observable)
}
func add(observer: ZObserver, observable: ZObservable) {
_lock.lock()
defer { _lock.unlock() }
if let objectSet = self.table.object(forKey: observable) {
objectSet.add(observer)
}
else {
let objectSet = ZWeakSet<AnyObject>()
objectSet.add(observer as AnyObject)
self.table.setObject(objectSet, forKey: observable)
}
}
func remove(observer: ZObserver, observable: ZObservable) {
_lock.lock()
defer { _lock.unlock() }
if let objectSet = self.table.object(forKey: observable) {
objectSet.remove(observer)
if objectSet.objects.count == 0 {
self.table.removeObject(forKey: observable)
}
}
}
public var observables: [ZObservable] {
var observables = [ZObservable]()
for observable in self.table.keyEnumerator() {
if let observable = observable as? ZObservable {
observables.append(observable)
}
}
return observables
}
}
@codelynx
Copy link
Copy Markdown
Author

codelynx commented Nov 6, 2016

This component uses ZWeakSet that can be obtained by following URL.
https://gist.github.com/codelynx/bc9f1e6129664e96b8c4de43913bc777

@codelynx
Copy link
Copy Markdown
Author

codelynx commented Nov 7, 2016

Usage:

class MyObserver: ZObserver {
	func observableDidChange(_ observable: ZObservable) {
		print("subject `\(observable)` did change !!")
	}
}

class YourObject: ZObservable {
	var value = 0 {
		didSet { self.observableDidChange() }
	}
}

let observer = MyObserver()
let yourObject = YourObject()

observer.addObservable(yourObject)
yourObject.value = 3 // "subject `MyObject` did change !!"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment