我需要在许多不同类型的不同视图控制器上对viewWillAppear
运行身份验证检查,但我显然不希望每次都重新键入它。我还需要添加一个处理程序变量来将其传递给viewWillDisappear
以结束检查。
我可以通过扩展或协议(或其他方式)执行此操作,以便我可以简单地包含一些内容(使用AuthCheck标记我需要运行函数):
class ForumLanderViewController: UIViewController, AuthCheck {}
我的想法是将它挂钩在幕后,这样我就可以添加一个属性,它将自动为这个控制器实现,而不必在类本身中实现变量或函数。
我想到使用扩展来向现有类添加新函数,但是我如何挂钩viewWillAppear
和viewWillDisappear
,并在特定视图控制器之间传递变量。一个简单,干燥的方式?
答案 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
的自定义版本,并且应该执行您想要的操作。