swift runtime实现 事件传递工具组件的 封装
2017-11-14 本文已影响44人
LiYaoPeng
一、对于多层逆传
- 在开发过程中,避免不了事件、数据的逆传,因为喜欢,所以大多数逆传都至少要串4层,而这些都用block、代理传递?想像一下你要定义多少的block属性、方法,或者代理对象、协议?崩溃!
- 多层逆传,如果用通知,那肯定很爽,但是会浪费很多的内存空间,消耗性能。
二、组件思路
- 其实与其说组件不如说是一个工具,因为他确实很小。
- 在NSObject分类中,添加一个block属性,这个属性要用懒加载
- 对外暴露两个方法,一个是发送信息的方法,另外一个是接受发送的消息的方法。
三、实际代码
代码不多,但是却是省去了很多代码
1. 定义block类型
block有两个参数:
signalKey
:区分事件的key
messageObj
: 传递的数据
typealias EVENTCALLBACKBLOCK = (_ signalKey: String, _ messageObj: Any)->(Any)?
2. 发送消息函数
发送消息函数参数
signalKey
: 区分事件的key
message
: 传递的数据
return
: 返回的数据
``
@discardableResult
public func sendSignalFunc (signalKey SignalKey: String, message Message: Any) -> (Any)? {
var eventBlock: EVENTCALLBACKBLOCK? = objc_getAssociatedObject(self, NSObectEventTransmitExtension.EVENTCALLBACKBLOCKKEY) as? EVENTCALLBACKBLOCK
if (eventBlock == nil) {
eventBlock = {(SignalKey, Message) -> (Any)? in
print("\(self)暂时没有,注册对赢得block,请检查,你想传传递的信息为: \n\n: SignalKey: \(SignalKey)\n\n,Message: \(Message)")
}
}
print("👌\(self):\(SignalKey)")
return eventBlock!(SignalKey,Message) as (Any)?
}
**3. 接收消息的函数
参数:
eventCallBack
这里写出你要的事件
在外层的类中调用
func receivedSignalFunc(eventCallBack: @escaping EVENTCALLBACKBLOCK) {
objc_setAssociatedObject(self, NSObectEventTransmitExtension.EVENTCALLBACKBLOCKKEY, eventCallBack, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
4. 快速搭建通道
func stitchChannelFunc(sender Sender: NSObject?) {
if Sender == nil {
print("🌶::sender为你nil\(self)")
return
}
Sender!.receivedSignalFunc { (signalKey, message) -> (Any)? in
return self.sendSignalFunc(signalKey: signalKey, message: message)
}
}
更新: 2018.4.9
解决问题: 无法推断类型。
比如我们在顶层viewController 用 receivedSignalFunc 对对应的对象的 block进行赋值。但是传递的block中的 message 的类型是翻译不出来的
vc.receivedSignalFunc { (signalKey, message) -> (Any)? in
if signalKey == "😁虾" {
//message 是any类型
if let message = message as? String {
print(signalKey + message)
}
}
return "老胡,收到了!!!"
}
需求是在这个地方可以推断出类型
更新:2018.5.5
类型推断代码封装:
extension NSObject {
/// 判断对象类型
/// 接受到消息的时候,可以通过这个方法进行匹配,其实内部就是做了 基本的 if let 判断
///
/// - Parameters:
/// - key: 对比 事件key
/// - eventKey: 传递过来的evnetkey
/// - type: object 猜测的类型
/// - objec: 猜测类型的对象
/// - succeed: 类型转化成功
/// - failure: 类型转化失败 objc为传入的objc
/// - Returns: 类型转化后的objc对象
@discardableResult
open class func eventMatching<T>( key:String,
eventKey: String,
type:T.Type,
objc: Any,
succeed:((_ self_T: T)->())?,
failure: ((_ objc:Any)->())? = nil) -> T? {
if key.isEqual(eventKey) {
return conversionType(type: type,
objc: objc,
succeed: succeed,
failure: failure)
}
return nil
}
/// 判断对象类型 内部就是做了 基本的 if let 判断
///
/// - Parameters:
/// - type: object 的类型
/// - objec: 一个对象
/// - succeed: 类型转化成功
/// - failure: 类型转化失败 objc为传入的objc
/// - Returns: 类型转化后的objc对象
@discardableResult
open class func conversionType<T>(type:T.Type ,
objc: Any,
succeed:((_ self_T: T)->())?,
failure: ((_ objc:Any)->())?) -> T? {
if let objc_T = objc as? T {
succeed?(objc_T)
return objc_T
}
#if DEBUG
let objecMessage = NSStringFromClass((objc as AnyObject).classForCoder)
print("\n 🌶🌶🌶 类型转化出错 《\(objecMessage)》 " + "无法转化为" + " 《\(T.self)》 " + "类型\n" + " \n🌶objc为:\n" + "\(objc)\n🌶")
#endif
failure?(objc)
return nil
}
}
- 事件传递成功log输出:
- 其中key 为用于区分事件的key:String
PYView -> PYViewController2 -> PYViewController
为一个事件传递的顺序
- 类型推断不符合log打印:
《NSString》
表示objc的真实类型,《Int》
为假设的类型objc 为传入的message的内容的打印