Skip to content

Instantly share code, notes, and snippets.

@chakrit
Last active February 17, 2016 11:45
Show Gist options
  • Save chakrit/216be5a8a6e142d660e8 to your computer and use it in GitHub Desktop.
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.
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)
}
}
// 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