内容简介:1. dispatch_once替代方案OC中用来保证代码块只执行一次的dispatch_once在swfit中已经被废弃了,取而代之的是使用static let,let本身就带有线程安全性质的.例如单例的实现.
1. dispatch_once替代方案
OC中用来保证代码块只执行一次的dispatch_once在swfit中已经被废弃了,取而代之的是使用static let,let本身就带有线程安全性质的.
例如单例的实现.
final public class MySingleton { static let shared = MySingleton() private init() {} }
但如果我们不想定义常量,需要某个代码块执行一次呢?
private lazy var takeOnceTime: Void = { // 代码块... }() _ = takeOnceTime
定义一个懒加载的变量,防止在初始化的时候被执行.后面加一个void,为了在_ = takeOnceTime赋值时不耗性能,返回一个Void类型.
lazy var改为static let也可以,为了使用方便,我们用一个类方法封装下
class ClassName { private static let takeOnceTime: Void = { // 代码块... }() static func takeOnceTimeFunc() { ClassName.takeOnceTime } } // 使用 ClassName.takeOnceTimeFunc()
这样就可以做到和dispatch_once一样的效果了.
2. 被废弃的+load()和+initialize()
我们都知道OC中两个方法+load()和+initialize().
+load(): app启动的时候会加载所有的类,此时就会调用每个类的load方法.
+initialize(): 第一次初始化这个类的时候会被调用.
然而在目前的swift版本中这两个方法都不可用了,那现在我们要在这个阶段搞事情该怎么做? 例如method swizzling.
JORDAN SMITH大神给出了一种很巧解决方案.UIApplication有一个next属性,它会在applicationDidFinishLaunching之前被调用,这个时候通过runtime获取到所有类的列表,然后向所有遵循SelfAware协议的类发送消息.
extension UIApplication { private static let runOnce: Void = { NothingToSeeHere.harmlessFunction() }() override open var next: UIResponder? { // Called before applicationDidFinishLaunching UIApplication.runOnce return super.next } } protocol SelfAware: class { static func awake() } class NothingToSeeHere { static func harmlessFunction() { let typeCount = Int(objc_getClassList(nil, 0)) let types = UnsafeMutablePointer <anyclass> .allocate(capacity: typeCount) let autoreleasingTypes = AutoreleasingUnsafeMutablePointer <anyclass> (types) objc_getClassList(autoreleasingTypes, Int32(typeCount)) for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() } types.deallocate() } } </anyclass> </anyclass>
之后任何遵守SelfAware协议实现的+awake()方法在这个阶段都会被调用.
3. 交换方法 Method Swizzling
黑魔法Method Swizzling在swift中实现的两个困难点
-
swizzling 应该保证只会执行一次.
-
swizzling 应该在加载所有类的时候调用.
分别在上面给出了解决方案.
下面给出了两个示例供参考:
protocol SelfAware: class { static func awake() static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) } extension SelfAware { static func swizzlingForClass(_ forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) { let originalMethod = class_getInstanceMethod(forClass, originalSelector) let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) guard (originalMethod != nil && swizzledMethod != nil) else { return } if class_addMethod(forClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!)) { class_replaceMethod(forClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!)) } else { method_exchangeImplementations(originalMethod!, swizzledMethod!) } } } class NothingToSeeHere { static func harmlessFunction() { let typeCount = Int(objc_getClassList(nil, 0)) let types = UnsafeMutablePointer <anyclass> .allocate(capacity: typeCount) let autoreleasingTypes = AutoreleasingUnsafeMutablePointer <anyclass> (types) objc_getClassList(autoreleasingTypes, Int32(typeCount)) for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() } types.deallocate() } } extension UIApplication { private static let runOnce: Void = { NothingToSeeHere.harmlessFunction() }() override open var next: UIResponder? { UIApplication.runOnce return super.next } } </anyclass> </anyclass>
在SelfAware的extension中为swizzlingForClass做了默认实现,相当于一层封装.
1. 给按钮添加点击计数
extension UIButton: SelfAware { static func awake() { UIButton.takeOnceTime } private static let takeOnceTime: Void = { let originalSelector = #selector(sendAction) let swizzledSelector = #selector(xxx_sendAction(action:to:forEvent:)) swizzlingForClass(UIButton.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector) }() @objc public func xxx_sendAction(action: Selector, to: AnyObject!, forEvent: UIEvent!) { struct xxx_buttonTapCounter { static var count: Int = 0 } xxx_buttonTapCounter.count += 1 print(xxx_buttonTapCounter.count) xxx_sendAction(action: action, to: to, forEvent: forEvent) } }
2. 替换控制器的viewWillAppear方法
extension UIViewController: SelfAware { static func awake() { swizzleMethod } private static let swizzleMethod: Void = { let originalSelector = #selector(viewWillAppear(_:)) let swizzledSelector = #selector(swizzled_viewWillAppear(_:)) swizzlingForClass(UIViewController.self, originalSelector: originalSelector, swizzledSelector: swizzledSelector) }() @objc func swizzled_viewWillAppear(_ animated: Bool) { swizzled_viewWillAppear(animated) print("swizzled_viewWillAppear") } }
本文收录于 SwiftTips
如有疑问,欢迎留言 :-D
作者:Dariel
链接:https://www.jianshu.com/p/23ea81be5cc2
以上所述就是小编给大家介绍的《交换方法Method Swizzling[swift]》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 在 JavaScript 中交换变量的 4 种方法
- 网络设备运维:盘点交换机常见8大故障及维修方法
- 使用位运算、值交换等方式反转java字符串-共四种方法
- 为您的 NIEM 交换建模
- RabbitMQ消息交换模式简介
- DSMM之数据交换安全
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript实战手册
David Sawyer McFarland / 李强 / 机械工业出版社 / 2009 / 89.00元
在《JavaScript实战手册》中,畅销书作者David McFarland教你如何以高级的方式使用JavaScript,即便你只有很少或者没有编程经验。一旦掌握了这种语言的结构和术语,你将学习如何使用高级的JavaScript工具来快速为站点添加有用的交互,而不是一切从头开始编写脚本。和其他的Missing Manuals图书不同,《JavaScript实战手册》清楚、精炼,手把手地讲解。 ......一起来看看 《JavaScript实战手册》 这本书的介绍吧!