Skip to content

Instantly share code, notes, and snippets.

@ColinEberhardt
Created February 11, 2015 09:15
Show Gist options
  • Star 42 You must be signed in to star a gist
  • Fork 12 You must be signed in to fork a gist
  • Save ColinEberhardt/05fafaca143ac78dbe09 to your computer and use it in GitHub Desktop.
Save ColinEberhardt/05fafaca143ac78dbe09 to your computer and use it in GitHub Desktop.
An eventing mechanism for Swift
/// An object that has some tear-down logic
public protocol Disposable {
func dispose()
}
/// An event provides a mechanism for raising notifications, together with some
/// associated data. Multiple function handlers can be added, with each being invoked,
/// with the event data, when the event is raised.
public class Event<T> {
public typealias EventHandler = T -> ()
private var eventHandlers = [Invocable]()
public init() {
}
/// Raises the event, invoking all handlers
public func raise(data: T) {
for handler in self.eventHandlers {
handler.invoke(data)
}
}
/// Adds the given handler
public func addHandler<U: AnyObject>(target: U, handler: (U) -> EventHandler) -> Disposable {
let wrapper = EventHandlerWrapper(target: target, handler: handler, event: self)
eventHandlers.append(wrapper)
return wrapper
}
}
// MARK:- Private
// A protocol for a type that can be invoked
private protocol Invocable: class {
func invoke(data: Any)
}
// takes a reference to a handler, as a class method, allowing
// a weak reference to the owning type.
// see: http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/
private class EventHandlerWrapper<T: AnyObject, U> : Invocable, Disposable {
weak var target: T?
let handler: T -> U -> ()
let event: Event<U>
init(target: T?, handler: T -> U -> (), event: Event<U>){
self.target = target
self.handler = handler
self.event = event;
}
func invoke(data: Any) -> () {
if let t = target {
handler(t)(data as U)
}
}
func dispose() {
event.eventHandlers = event.eventHandlers.filter { $0 !== self }
}
}
@klaas
Copy link

klaas commented May 24, 2015

How about automatically disposing the EventHandlerWrapper when the target reference is nil within the invoke method?

@galblank
Copy link

galblank commented Mar 4, 2016

it seems that this method only works on simple types such as int / string etc..
how about Arrays and Dictionaries?

@nhatlee
Copy link

nhatlee commented Sep 9, 2016

It is great to start writing KVO. But how to remove the observer?

@Jcarto
Copy link

Jcarto commented Nov 21, 2016

I am getting a build error on the eventHandlers.
in the dispose function it is saying that eventHandlers is inaccessible due to the private protection level, but you can't remove private because of the [Invocables] ...

Ideas how to fix?

@Vladlex
Copy link

Vladlex commented Nov 25, 2016

Make if file private:
fileprivate var eventHandlers = [Invocable]()

Ideas how to fix?

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