Skip to content

Instantly share code, notes, and snippets.

@wildthink
Last active February 24, 2019 19:32
Show Gist options
  • Save wildthink/fa824de45aacc2fed89aae0fe2cf0370 to your computer and use it in GitHub Desktop.
Save wildthink/fa824de45aacc2fed89aae0fe2cf0370 to your computer and use it in GitHub Desktop.
Dynamic dependency injection
//
// DomainContext.swift
//
// Copyright (c) 2019 Jason Jobe. All rights reserved.
// https://gist.github.com/wildthink/fa824de45aacc2fed89aae0fe2cf0370
//
// Created by Jason Jobe on 5/11/15.
// Derived from Relay.swift
// Copyright (c) 2015, 2016 Jason Jobe. All rights reserved.
// https://gist.github.com/wildthink/acfdf82c2625dc73ad6e42d399d91846
//
/* Example usage
protocol MyProtocol {
func someClassOrProtocolFunction (some:Int, args:[String])
}
relay (MyProtocol.self) {
$0.someClassOrProtocolFunction(some, args)
}
relay { (target: MyProtocol) in
target.someClassOrProtocolFunction(some, args)
}
Domain Chain Resolution
View -> Controller -> WindowController -> [nextResponder] -> NSApp -> AppDelegate
*/
import Foundation
#if os(iOS)
import UIKit.UIResponder
public typealias Responder = UIResponder
public typealias Application = UIApplication
public typealias Controller = UIViewController
#else
import AppKit.NSResponder
public typealias Responder = NSResponder
public typealias Application = NSApplication
public typealias Controller = NSViewController
#endif
@objc public protocol DomainContext: class {
func domainContext(type: AnyClass, chain: NSMutableArray?) -> Any?
}
extension Responder: DomainContext {
public func domainContext(type ac: AnyClass, chain: NSMutableArray?) -> Any? {
chain?.add(self)
if self.isKind(of: ac) { return self }
return nextResponder?.domainContext(type: ac, chain: chain)
}
}
extension Application {
public override func domainContext(type ac: AnyClass, chain: NSMutableArray?) -> Any? {
chain?.add(self)
if self.isKind(of: ac) { return self }
if let r = delegate as? DomainContext { return r.domainContext(type:ac, chain: chain) }
// In case the delegate is not a DomainContext
if (delegate?.isKind(of: ac) ?? false) {
chain?.add(delegate as Any)
return delegate
}
return nil
}
}
#if os(macOS)
extension NSWindowController {
public override func domainContext(type ac: AnyClass, chain: NSMutableArray?) -> Any? {
chain?.add(self)
if self.isKind(of: ac) { return self }
if let dc = nextResponder?.domainContext(type: ac, chain: chain) { return dc }
return NSApp.domainContext(type: ac, chain: chain)
}
}
#endif
extension Controller {
public override func domainContext(type ac: AnyClass, chain: NSMutableArray?) -> Any? {
chain?.add(self)
if self.isKind(of: ac) { return self }
return parent?.domainContext(type: ac, chain: chain)
?? nextResponder?.domainContext(type: ac, chain: chain)
}
}
// Mark - Swifty API
// public extension NSObjectProtocol where Self: Controller {
extension DomainContext {
func domain<C: AnyObject>(as type: C.Type, chain: NSMutableArray? = nil) -> C? {
return domainContext(type: C.self, chain: chain) as? C
}
func relay <T: AnyObject> (_ type: T.Type, call: (T) -> Void) -> Void {
if let target = domain(as: T.self) { call (target) }
}
func recall <T: AnyObject, R> (_ type: T.Type, call: (T) -> R?) -> R? {
if let target = domain(as: T.self) { return call (target) }
return nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment