在大多数viewWillAppear调用上运行函数

时间:2017-11-19 21:40:12

标签: ios swift

我需要在许多不同类型的不同视图控制器上对viewWillAppear运行身份验证检查,但我显然不希望每次都重新键入它。我还需要添加一个处理程序变量来将其传递给viewWillDisappear以结束检查。

我可以通过扩展或协议(或其他方式)执行此操作,以便我可以简单地包含一些内容(使用AuthCheck标记我需要运行函数):

class ForumLanderViewController: UIViewController, AuthCheck {}

我的想法是将它挂钩在幕后,这样我就可以添加一个属性,它将自动为这个控制器实现,而不必在类本身中实现变量或函数。

我想到使用扩展来向现有类添加新函数,但是我如何挂钩viewWillAppearviewWillDisappear,并在特定视图控制器之间传递变量。一个简单,干燥的方式?

2 个答案:

答案 0 :(得分:0)

您可以使用Method Swizzling http://nshipster.com/method-swizzling/

  

方法调配是改变执行的过程   现有选择器。这是一种通过以下事实实现的技术   Objective-C中的方法调用可以在运行时更改   改变选择器如何映射到类中的底层函数   派遣表。

     

例如,假设我们想跟踪每个视图的次数   控制器在iOS应用程序中呈现给用户:

     

每个视图控制器都可以将跟踪代码添加到自己的实现中   viewDidAppear:,但这将导致大量的重复   样板代码。子类化将是另一种可能性,但它   需要子类化UIViewController,UITableViewController,   UINavigationController,以及其他所有视图控制器类   也会遭受代码重复的方法。

     

幸运的是,还有另一种方法:从类别中调整方法。

以下是如何操作:

private let swizzling: (UIViewController.Type) -> () = { viewController in

    let originalSelector = #selector(viewController.viewWillAppear(_:))
    let swizzledSelector = #selector(viewController.proj_viewWillAppear(animated:))

    let originalMethod = class_getInstanceMethod(viewController, originalSelector)
    let swizzledMethod = class_getInstanceMethod(viewController, swizzledSelector)

    method_exchangeImplementations(originalMethod, swizzledMethod) }

extension UIViewController {

    open override class func initialize() {
        // make sure this isn't a subclass
        guard self === UIViewController.self else { return }
        swizzling(self)
    }

    // MARK: - Method Swizzling

    func proj_viewWillAppear(animated: Bool) {
        self.proj_viewWillAppear(animated: animated)

        let viewControllerName = NSStringFromClass(type(of: self))
        print("viewWillAppear: \(viewControllerName)")
    } 
 }

答案 1 :(得分:0)

协议允许您定义所有符合对象的方法/属性集。

协议对您没有任何好处,因为您想为基类UIViewController中已存在的方法创建行为。

Extensions允许您向对象添加方法/属性,可能在定义该对象的文件之外。但是,除非将该代码绑定到公共基类,否则不能在多个类之间共享扩展中的代码。

正如@Taier在他们的回答中所说,你可以使用方法调配来取代viewWillAppear的实现,但我不建议这样做。它依赖于Objective-C消息调度和Objective-C运行时的细节,我怀疑它将在未来几年内逐步淘汰。

如果您可以使所有类继承自公共基类,那么您可以在该基类中创建viewWillAppear的自定义版本,并且应该执行您想要的操作。