Skip to content

Instantly share code, notes, and snippets.

@rizumita
Last active February 22, 2016 14:00
Show Gist options
  • Save rizumita/d8d48eca74137fed1c1e to your computer and use it in GitHub Desktop.
Save rizumita/d8d48eca74137fed1c1e to your computer and use it in GitHub Desktop.
SegueOperatorはSegueに取り付けられる交換手クラスです。BundlesWireframeはVIPERアーキテクチャの遷移を司るクラスです。
/*
* SwinjectでSegueにInjectするSegueOperatorTypeを指定する。
* nameにSegueのIdentifierを指定する。
*/
container.register(SegueOperatorType.self, name: "BundlesSegue") { _ in
return SegueOperator {
_, _ in
print("test")
}
}
import UIKit
/*
* VIPERアーキテクチャのWireframe。遷移を担当する。
* Wireframeを利用せずにViewController内部で全ての処理を行っても良いのですが、遷移元のコントローラが遷移先の情報を持つようにしたくなかったのでWireframeを利用しています。
*/
class BundlesWireframe: BundlesWireframeType {
var viewController: BundlesViewController?
/*
* 遷移するときにViewControllerから呼ぶ
*/
func showBundle(withID id: String?) {
let segueOperator = SegueOperator { (s, d: BundleViewController) in
d.id = id
} # 引数のクロージャでdestinationViewControllerを設定する
viewController?.performSegueWithIdentifier(R.segue.bundlesViewController.bundleSegue.identifier,
sender: segueOperator) # senderにSegueOperatorを渡す
}
}
protocol BundlesWireframeType: WireframeType {
var viewController: BundlesViewController? { get set }
func showBundle(withID id: String?)
}
protocol WireframeType: class {
/*
* ViewControllerのprepareForSegueから呼ぶ
*/
func prepare(forSegue segue: UIStoryboardSegue, sender: AnyObject?)
}
extension WireframeType {
func prepare(forSegue segue: UIStoryboardSegue, sender: AnyObject?) {
switch sender {
case let segueOperator as SegueOperatorType:
segue.segueOperator = segueOperator
default: ()
}
}
}
import UIKit
protocol SegueOperatorType: class {
func operate(source source: UIViewController, destination: UIViewController)
}
/*
* UIStoryboardSegueに取り付ける交換手クラス
*/
class SegueOperator<Source: UIViewController, Destination: UIViewController>: SegueOperatorType {
typealias Operation = (Source, Destination) -> ()
let operation: Operation
init(operation: Operation) {
self.operation = operation
}
func operate(source source: UIViewController, destination: UIViewController) {
operation(source as! Source, destination as! Destination)
}
}
#
# UIStoryboardSegueにSegueOperatorTypeを取り付けられるようにする
# UIStoryboardSegueが作成された時にDIコンテナからSegueOperatorTypeをInjectする
#
import ObjectiveC
var AssociatedObjectHandle: UInt8 = 0
extension UIStoryboardSegue {
var segueOperator: SegueOperatorType? {
get {
return objc_getAssociatedObject(self, &AssociatedObjectHandle) as? SegueOperatorType
}
set {
objc_setAssociatedObject(self, &AssociatedObjectHandle, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
dynamic func performSwizzled() {
segueOperator?.operate(source: sourceViewController, destination: destinationViewController)
performSwizzled()
}
dynamic convenience init(swizzled_identifier: String?, source: UIViewController, destination: UIViewController) {
self.init(swizzled_identifier: swizzled_identifier, source: source, destination: destination)
segueOperator = assembler.resolver.resolve(SegueOperatorType.self, name: identifier)
}
override public class func initialize() {
super.initialize()
struct Static {
static var token: dispatch_once_t = 0;
}
// make sure this isn't a subclass
dispatch_once(&Static.token) {
swizzlePerform()
swizzleInit()
}
}
private static func swizzlePerform() {
let originalSelector = Selector("perform");
let swizzledSelector = Selector("performSwizzled");
swizzle(self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}
private static func swizzleInit() {
let originalSelector = Selector("initWithIdentifier:source:destination:");
let swizzledSelector = Selector("initWithSwizzled_identifier:source:destination:");
swizzle(self, originalSelector: originalSelector, swizzledSelector: swizzledSelector)
}
}
private func swizzle(cls: AnyClass!, originalSelector: Selector, swizzledSelector: Selector) {
let originalMethod = class_getInstanceMethod(cls, originalSelector);
let swizzledMethod = class_getInstanceMethod(cls, swizzledSelector);
let didAddMethod = class_addMethod(cls, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
if didAddMethod {
class_replaceMethod(cls, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment