URL Handle in Swift (二) — 响应链处理 URL

最后更新: Swift4时候的博客,以前在 CMD markdown 上编辑的,现在搬到这里

上篇文章-URL Handle in Swift (一) -- URL 分解中,我们已经将URL进行了分解, 信息全部保存在了IGInstruction类型之中. 在这篇文章之后, 我们将讨论如何构建一个类似iOS响应者链来处理IGInstruction

一、响应者链

iOS响应者链相关的知识在网络上一大把。 这里我就简单的说明一下。 UIApplicationUIViewUIViewController 继承于 UIResponder, UIResponder中有一个 next, 表示在响应者链上的下一个响应者。

  1. UIApplication.nextnil
  2. UIWindow.nextUIApplication, UIView.nextSuperView 或者 UIViewController;
  3. UIViewController.next 情况就比较的复杂了:
  • UIWindow.rootViewController.next 为 UIWindow`;
  • 通过 present(, animated:, completion:)出来的 VC, nextpresentedViewController;
  • 通过 navigationController?.pushViewController(, animated:)出来的 出来的 VC, nextnavigationController;
  • UITabbarController管理的 viewControllers, nextUITabbarController;
  • UIPageViewController管理的 viewControllers, nextUIPageViewController;

在处理 URL 过程中, 我们也仅仅需要考虑找到合适的 Responder, 然后执行响应的操作。实际上, 我们还可以简化一点, 因为在实际的开发中, 当接收到一个 URL, 最常见的就是弹出一个对应的控制器来进行操作。

二、寻找合适 Responder

首先定义一个 IGNode 协议,

import Foundation

public enum IGHandlerAction {
    case ignoring
    case handling(()->Void)
}

protocol IGHandlerable {
    func handler(forIns instruction: IGInstruction) -> IGHandlerAction
}

extension IGHandlerAction {
    
    @discardableResult
    public func handle() -> Bool {
        switch self {
        case .handling(let handler):
            handler()
        default:
            break
        }
        return self.isHandling
    }
    
    public var isHandling: Bool {
        switch self {
        case .handling(_):
            return true
        case .ignoring:
            return false
        }
    }
    
    public var hasAction: Bool {
        switch self {
        case .handling(_):
            return true
        default:
            return false
        }
    }
}


protocol IGNode {
    
    var igHanderable: IGHandlerable? { get }
    
    var firstIGNode: IGNode { get }
    
    var nextIGNode: IGNode? { get }
    
    func handlerInChain(forIG instruction: IGInstruction, fromFirstNode: Bool) -> IGHandlerAction
}

extension IGNode where Self: UIResponder {
    
    var nextIGNode: IGNode? {
        
        var next = self.next
        while next != nil {
            if let node = next as? IGNode {
                return node
            }
            next = next?.next
        }
        return nil
    }
}

extension IGNode {
    
    func handlerInChain(forIG instruction: IGInstruction, fromFirstNode: Bool) -> IGHandlerAction {
        if fromFirstNode {
            return self.firstIGNode.handlerInChain(forIG: instruction, fromFirstNode: false)
        } else {
            if let action = self.igHanderable?.handler(forIns: instruction), action.isHandling {
                return action
            } else {
                return self.nextIGNode?.handlerInChain(forIG: instruction, fromFirstNode: false) ?? .ignoring
            }
        }
    }
    var firstIGNode: IGNode { return self }
}

UIViewController + IGNode

extension UIViewController: IGNode {
    
    var igHanderable: IGHandlerable? {
        return !self.ignoreIG ? (self as? IGHandlerable) : nil
    }
    
    @objc open var ignoreIG: Bool { return self.presentedViewController != nil }
    
    var firstIGNode: IGNode {
        if let presented = self.presentedViewController {
            return presented.firstIGNode
        } else {
            return currentChildViewController?.firstIGNode ?? self
        }
    }
    
    @objc open var currentChildViewController: UIViewController? {
        return nil
    }
}

extension UINavigationController {
    
    @objc open override var currentChildViewController: UIViewController? {
        return self.topViewController
    }
}

extension UITabBarController {
    
    @objc open override var currentChildViewController: UIViewController? {
        return self.selectedViewController
    }
}

extension UIPageViewController {
    
    @objc open override var currentChildViewController: UIViewController? {
        return self.viewControllers?.first ?? self
    }
}

上一篇:通过当前view得到所在的viewcontroller


下一篇:govendor 使用