Last active
February 17, 2016 11:45
-
-
Save chakrit/216be5a8a6e142d660e8 to your computer and use it in GitHub Desktop.
A single-file drop-in GCD-based strongly-typed Actor implementation in Swift.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
protocol Actable { | |
typealias MessageType | |
func act(cue: MessageType, replyTo channel: Channel<MessageType, Self>) | |
} | |
class Channel<TMessage, TActable: Actable where TActable.MessageType == TMessage> { | |
typealias CallbackType = (TMessage) -> Void | |
let uid: String | |
let actor: TActable | |
let queue: dispatch_queue_t | |
let callback: CallbackType | |
init?(actor: TActable, callback: CallbackType) { | |
self.uid = NSUUID().UUIDString | |
self.actor = actor | |
self.callback = callback | |
guard let queueName = self.uid.cStringUsingEncoding(NSUTF8StringEncoding) else { | |
self.queue = dispatch_get_main_queue() | |
return nil | |
} | |
self.queue = dispatch_queue_create(queueName, DISPATCH_QUEUE_SERIAL) | |
} | |
func cue(message: TMessage) { | |
dispatch_async(self.queue) { [weak self] () -> Void in | |
guard let s = self else { return } | |
s.actor.act(message, replyTo: s) | |
} | |
} | |
func reply(message: TMessage) { | |
dispatch_async(dispatch_get_main_queue()) { [weak self] () -> Void in | |
self?.callback(message) | |
} | |
} | |
} | |
final class Actor { | |
static func start<TMessage, TActable: Actable where TActable.MessageType == TMessage>(actor: TActable, callback: (TMessage) -> Void) -> Channel<TMessage, TActable>? { | |
return Channel(actor: actor, callback: callback) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// EXAMPLE USAGE | |
import Foundation | |
final class Conductor { | |
enum Cues { | |
case Start | |
case Stop | |
// input | |
case QueueSong(song: String) | |
// output | |
case Note(note: String) | |
case Ensemble | |
case Chorus | |
// case WhatHaveYou | |
} | |
} | |
extension Conductor: Actable { | |
typealias MessageType = Cues | |
func act(cue: MessageType, replyTo channel: Channel<MessageType, Conductor>) { | |
switch cue { | |
case .Start: | |
break | |
case .Stop: | |
break | |
case let .QueueSong(song): | |
print("play song: \(song)") | |
channel.reply(.Note("do")) | |
channel.reply(.Note("re")) | |
channel.reply(.Note("mi")) | |
break | |
default: // ignore own replies | |
break | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment