URL Handle in Swift (二) — 响应链处理 URL
最后更新: Swift4时候的博客,以前在 CMD markdown 上编辑的,现在搬到这里
更新日期: 2018-06-06
在上篇文章-URL Handle in Swift (一) -- URL 分解中,我们已经将URL进行了分解, 信息全部保存在了IGInstruction类型之中. 在这篇文章之后, 我们将讨论如何构建一个类似iOS响应者链来处理IGInstruction。
一、响应者链
iOS响应者链相关的知识在网络上一大把。 这里我就简单的说明一下。 UIApplication、UIView、UIViewController 继承于 UIResponder, UIResponder中有一个 next, 表示在响应者链上的下一个响应者。
-
UIApplication.next为nil -
UIWindow.next为UIApplication,UIView.next为SuperView或者UIViewController; -
UIViewController.next情况就比较的复杂了:
-
UIWindow.rootViewController.next 为 UIWindow`;
-
通过
present(, animated:, completion:)出来的VC,next为presentedViewController; -
通过
navigationController?.pushViewController(, animated:)出来的 出来的VC,next为navigationController; -
UITabbarController管理的viewControllers,next为UITabbarController; -
UIPageViewController管理的viewControllers,next为UIPageViewController;
在处理 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
}
}

浙公网安备 33010602011771号