Skip to content

Instantly share code, notes, and snippets.

@ZhangYiJiang
Last active February 7, 2017 04:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ZhangYiJiang/e113982dd5f4b979dd729b77bc7081f0 to your computer and use it in GitHub Desktop.
Save ZhangYiJiang/e113982dd5f4b979dd729b77bc7081f0 to your computer and use it in GitHub Desktop.
Typed events for Swift 3
//
// Event.swift
//
/**
Typed event implementation from <http://blog.scottlogic.com/2015/02/05/swift-events.html>
Updated and improved for Swift 3
## Usage
```
class Controller {
func someFunction() {
// Create an event
let event = Event<(String, String)>()
// Add a handler
let handler = event.addHandler(self, Controller.handleEvent)
// Raise the event
event.raise(("Colin", "Eberhardt"))
// Remove the handler
handler.dispose()
}
func handleEvent(first: String, second: String) {
println("Hello \(first), \(second)")
}
}
```
*/
class Event<EventArguments> {
typealias EventHandler = (EventArguments) -> Void
fileprivate var eventHandlers = [Invocable]()
func raise(_ data: EventArguments) {
for handler in eventHandlers {
handler.invoke(data: data)
}
}
/// Add a handler to listen to this event
///
/// - Parameters:
/// - target: The object on which the handler is attached
/// - handler: A class method on the target object to call when the event is fired
@discardableResult
func addHandler<Target: AnyObject>(target: Target, handler: @escaping (Target) -> EventHandler) -> Disposable {
let wrapper = EventHandlerWrapper(target: target, handler: handler, event: self)
eventHandlers.append(wrapper)
return wrapper
}
}
private class EventHandlerWrapper<Target: AnyObject, EventArguments>: Invocable, Disposable {
typealias Handler = (Target) -> (EventArguments) -> Void
weak var target: Target?
let handler: Handler
let event: Event<EventArguments>
init(target: Target?, handler: @escaping Handler, event: Event<EventArguments>) {
self.target = target
self.handler = handler
self.event = event
}
func invoke(data: Any) {
if let t = target {
// swiftlint:disable:next force_cast
handler(t)(data as! EventArguments)
}
}
func dispose() {
event.eventHandlers = event.eventHandlers.filter { $0 !== self }
}
}
private protocol Invocable: class {
func invoke(data: Any)
}
protocol Disposable {
/// Remove the handler from the event
func dispose()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment