Skip to content

Instantly share code, notes, and snippets.

@sharplet
Last active April 5, 2017 07:54
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sharplet/34a4e893181469c20626f6abe0a2cdeb to your computer and use it in GitHub Desktop.
Save sharplet/34a4e893181469c20626f6abe0a2cdeb to your computer and use it in GitHub Desktop.
Simple GCD-based actors in Swift
import Dispatch
/// Wraps some `Base` type so that all method calls become
/// "message sends", e.g., `async { $0.foo() }` or `sync { $0.bar() }`.
public final class Actor<Base> {
private var instance: Base
private let queue: DispatchQueue
public init(_ instance: Base, target: DispatchQueue? = nil) {
self.instance = instance
self.queue = DispatchQueue(label: "me.sharplet.MethodActor.\(Actor.self).queue", target: target)
}
public func async(_ message: @escaping (inout Base) -> Void) {
queue.async {
message(&self.instance)
}
}
public func asyncAfter(deadline: DispatchTime, _ message: @escaping (inout Base) -> Void) {
queue.asyncAfter(deadline: deadline) {
message(&self.instance)
}
}
public func asyncAfter(wallDeadline: DispatchWallTime, _ message: @escaping (inout Base) -> Void) {
queue.asyncAfter(wallDeadline: wallDeadline) {
message(&self.instance)
}
}
public func sync<Result>(_ message: (inout Base) throws -> Result) rethrows -> Result {
return try queue.sync {
try message(&instance)
}
}
}
/// A simple app delegate that shows the network activity
/// indicator for 1 second whenever the app becomes active.
@UIApplicationMain
final class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func applicationDidBecomeActive(_ application: UIApplication) {
let indicator: Actor<NetworkActivityIndicator> = NetworkActivityIndicator.shared
indicator.async { $0.startActivity() }
indicator.asyncAfter(deadline: .now() + .seconds(1)) { $0.stopActivity() }
}
}
import UIKit
/// A shared actor to manage the network activity indicator.
/// The initialiser is private to enforce use of `NetworkActivityIndicator.shared`.
struct NetworkActivityIndicator {
static let shared = Actor(NetworkActivityIndicator(), target: .main)
private let application = UIApplication.shared
private var counter: Int
private init() {
counter = 0
}
mutating func startActivity() {
counter += 1
updateIndicator()
}
mutating func stopActivity() {
counter -= 1
updateIndicator()
}
private func updateIndicator() {
application.isNetworkActivityIndicatorVisible = isActive
}
var isActive: Bool {
return counter > 0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment