Last active
February 24, 2019 19:32
-
-
Save wildthink/fa824de45aacc2fed89aae0fe2cf0370 to your computer and use it in GitHub Desktop.
Dynamic dependency injection
This file contains hidden or 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
// | |
// 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