美文网首页Swift
Swift Umbrella 框架

Swift Umbrella 框架

作者: fuyoufang | 来源:发表于2019-11-12 12:00 被阅读0次

    Umbrella 是 Swift 下对数据分析的抽象层。作者受启发于 Moya

    为什么使用 Umbrella


    Umbrella 可以解决下面的问题:

    1. 当项目中使用多个数据分析库(SDK)时,则需要在数据统计的地方添加或更改各个框架的设置。而 Umbrella 框架,创建了一个抽象层,对项目中所有应用的数据分析库(SDK)进行了统一的管理,只需要调用一个方法,就可以将事件传递到所有的数据分析库。

    2. 常用的数据分析库(SDK),通常会采用字符串来设置统计事件的名称,使用字典来设置事件参数。这种方式无法通过编译器来保证代码的正确性。而 Umbrella 框架,采用了 Enum 枚举的方式标记统计事件,枚举值提供事件的名称和参数。

    具体使用方法可以通过 Github 查看。

    从 Umbrella 中得到的启发


    在不确定的情况下,操作相应的类

    Umbrella 对常见的几种数据分析库进行了封装,当用户在项目中恰好使用这些库时,就可以通过简单的设置完成配置。但是 Umbrella 怎么知道用户会使用哪些数据分析库呢?在不确定的情况下,怎样封装对应的类呢?

    Umbrella 使用了运行时的特性,通过字符串记录了常用的数据分析 SDK 中的类名和初始化方法名。如果用户恰好使用了 Umbrella 中内置的几种数据分析 SDK,则可以通过类名和方法名来获取到对应的类和方法。具体实现如下:

    public protocol RuntimeProviderType: ProviderType {
        // 记录数据分析的类名
        var className: String { get }
        // 初始化数据分析实例的方法名(因为有些数据分析全部使用静态方法,并不需要初始化一个实例,所以该属性为 optional)
        var instanceSelectorName: String? { get } // optional
        // 记录分析事件的方法名
        var selectorName: String { get }
    }
    
    public extension RuntimeProviderType {
        var cls: NSObject.Type? {
            return NSClassFromString(self.className) as? NSObject.Type
        }
        
        var instanceSelectorName: String? {
            return nil
        }
        
        /*
         * 字符串转化为 类
         * 字符串转化为 Selector
         * 类调用方法生成负责统计的 实例
         */
        var instance: AnyObject? {
            guard let cls = self.cls else { return nil }
            guard let sel = self.instanceSelectorName.flatMap(NSSelectorFromString) else { return nil }
            guard cls.responds(to: sel) else { return nil }
            // takeUnretainedValue 不负责对象的释放
            return cls.perform(sel)?.takeUnretainedValue()
        }
        
        // 统计 Selector
        var selector: Selector {
            return NSSelectorFromString(self.selectorName)
        }
        
        var responds: Bool {
            guard let cls = self.cls else { return false }
            if let instance = self.instance {
                return instance.responds(to: self.selector)
            } else {
                return cls.responds(to: self.selector)
            }
        }
        
        func log(_ eventName: String, parameters: [String: PrimitiveType]?) {
            guard self.responds else { return }
            // 调用两个参数的方法
            if let instance = self.instance {
                _ = instance.perform(self.selector, with: eventName, with: parameters)
            } else {
                _ = self.cls?.perform(self.selector, with: eventName, with: parameters)
            }
        }
    }
    

    对某个数据分析 SDK 进行封装时,我们只需要创建符合 RuntimeProviderType 的类型就可以了。比如:

    open class AppsFlyerProvider: RuntimeProviderType {
        public let className: String = "AppsFlyerTracker"
        public let instanceSelectorName: String? = "sharedTracker"
        public let selectorName: String = "trackEvent:withValues:"
        
        public init() {
        }
    }
    

    通过 Enum 让代码更可靠

    Swift 中 Enum 可以绑定参数,可以拥有方法。我们可以通过这些特性提高代码的可靠性。比如 Umbrella 就通过 Enum 来设置事件统计的名称,并绑定了事件统计的参数。

    相关文章

      网友评论

        本文标题:Swift Umbrella 框架

        本文链接:https://www.haomeiwen.com/subject/ubifictx.html