美文网首页
iOS-组件化

iOS-组件化

作者: JerrySi | 来源:发表于2019-08-08 10:42 被阅读0次

在做iOS组件化的时候,我没有找到像ARouter一样兼容性和使用性比较好的框架。经过权衡后,决定使用CTMediator来作为iOS组件化底层结构,再对CTMediator进行扩展来满足我们的要求。

扩展支持Swift跳转

Swift和OC在类和方法字符串展示上稍有不同:
类名:OC直接通过类名就能反射出Class,Swift有一套特殊格式生成
方法:OC直接通过action name就能反射出action,Swift需要加冒号:

  1. 类名扩展
open func transformString(targetName: String, isTargetClass: Bool, shouldCacheTarget:Bool = false) -> AnyObject? {
    
    var targetClass: AnyClass? = self.cachedTarget[targetName]
    if targetClass == nil {
        
        // 首先通过OC的方式去反射Class
        targetClass = NSClassFromString(targetName)
        if targetClass == nil {
            // 如果OC的方式反射失败,再使用Swift的方式
            targetClass = NSObject.swiftClassFromString(targetName)
        }
    }
    /***/
}

通过字符串去反射Class的时候,首先通过OC的方式,如果OC的方式反射失败,再使用Swift的方式。关键点就是swiftClassFromString是如何找回Swift 类名的:

extension NSObject {
    
    // create a static method to get a swift class for a string name
    @objc public class func swiftStringClassFromString(_ className: String, bundle: Bundle = Bundle.main) -> String? {
        // get the project name
        if  let appName = bundle.object(forInfoDictionaryKey: "CFBundleExecutable") as? String {
            // generate the full name of your class (take a look into your "YourProject-swift.h" file)
            let classStringName = "_TtC\(appName.utf16Length)\(appName)\(className.count)\(className)"
            // return the class!
            return classStringName
        }
        return nil
    }
    
    // create a static method to get a swift class for a string name
    public class func swiftClassFromString(_ className: String) -> AnyClass? {
        
        if let classStringName = NSObject.swiftStringClassFromString(className) {
            return NSClassFromString(classStringName)
        }
        return nil
    }
}

在我们项目中对NSObject进行扩展方法,在swiftStringClassFromString生成Swift类名。特别注意这个方法前面要加上@objc,让其通过OC方式调用。

  1. 方法扩展
    和获取Class的时候类似,先使用OC方式去查看是否能响应,没有响应再使用Swift方式去查看。否则处理异常。
fileprivate func performSelector(_ isTargetClass: Bool, targetName: String, actionName: String, params: Any, shouldCacheTarget: Bool, shouldReturn: Bool) -> Any? {
    /***/
    var action = NSSelectorFromString(actionString)
    // 通过OC方式去看是否响应该方法
    if target.responds(to:action) {
        let obj = target.perform(action, with:params)
        return shouldReturn ? obj?.takeUnretainedValue() : nil
    } else {
        // 有可能target是Swift对象
        actionString = actionName + ":"
        action = NSSelectorFromString(actionString)
        
        if target.responds(to:action) {
            let obj = target.perform(action, with:params)
            return shouldReturn ? obj?.takeUnretainedValue() : nil
        } else {
            /*无响应请求的地方*/
        }
    }
}

提供程序接口Provide

在iOS里面,该功能需要我们自己实现。这里我参考ARouter里面IProvide的实现方法实现了自己的一套提供程序接口。
在基础Module里面定义Provide方法,在具体Module里面继承该Provide后重写该方法。因为项目主项目肯定都包含这些具体Module的,所以可以在主项目里面初始化这些子类,并把父类里面公共对象指向子类。 以后直接调用父类里面公共对象就可以了。
talk is cheap, show me the code

  1. 基础Module里面父类
open class PassportModuleProvider {
    
    public static var shareInstance: PassportModuleProvider?
    
    public init() {
        PassportModuleProvider.shareInstance = self
    }
    
    open func passportUpdatePWD() {
        fatalError("子类实现passportUpdatePWD")
    }

    open func passportPrepareVC() -> UIViewController? {
        fatalError("子类实现passportPrepareVC")
    }
}
  1. 具体Module里面实现类
public class PassportProviderLmpl: PassportModuleProvider {
    open override func passportUpdatePWD() {
       /**/
    }
    open override func passportPrepareVC() -> UIViewController? {
        return UIViewController()
    }
}
  1. 主项目里初始化实现类
class func initProvider() {
    _ = PassportProviderLmpl()
    /***/
}

这样在初始化实现类的时候,就会自动把PassportModuleProvider.shareInstance指向PassportProviderLmpl了。然后使用的时候,通过该shareInstance就能在每个Module中调用实现类里面的方法了。

我一直在想能不能把主项目里初始化实现类这个步骤去除,没有想到特别好的方法。事实上虽然Swift无法像Android一样定义自己的注解,不过OC可以,只不过这里我们项目的原则是尽可能Swift,所以通过OC添加注解,再和Swift混编的方式我们就暂时没有使用。 不过如果你的项目是OC项目,那么第3步完全可以通过注解处理的。

页面跳转拦截

针对页面跳转拦截,iOS中我们之前已经使用RxSwift处理了这部分流程,所以这部分暂时还没有放入组件化中。不过这部分后续我会放入组件化中,到时候会更新本文章。


经过上面方式的处理,我们项目结构变成和Android类似的结构


image.png image.png

相关文章

  • iOS 组件化开发之CocoaPods创建私有库

    什么是组件化开发,我就不详细介绍了,网上可以找到很多资料.IOS-组件化架构漫谈这篇文章就比较全面的介绍了组件化开...

  • iOS-组件化

    一. 组件化 1. 组件化分析 支付宝的界面我们都很熟悉,它的每个模块都能做成一个APP了,支付宝的业务量之大也不...

  • iOS-组件化

    在做iOS组件化的时候,我没有找到像ARouter一样兼容性和使用性比较好的框架。经过权衡后,决定使用CTMedi...

  • iOS-组件化问题

    1、每次在验证索引文件时,podspec中的版本号必须和提交代码时候打的tag一致,不然验证不通过。 注意,千万不...

  • iOS-浅谈组件化

    前言 什么是组件化,为什么要有组件化,组件化跟我们的项目又有什么关系,或者说它能给我们的项目带来什么,我们带着疑问...

  • ios-组件化(模块化)开发

    - 实现组件化开发有哪几种方式? 通过静态库。 通过xcode创建多个子项目,最后合并成一个项目。 创建一个私有库...

  • iOS-组件化之路由方案

    组件化 业务模块层组件化的目标是为了实现不同业务模块之间的独立性,从而使业务开发更专注于单个模块.我倾向于利用co...

  • iOS-组件化的简单理解

    下图简单描述传统APP和组件化APP的区别。 1.传统的开发模式 传统的APP开发,需要多个开发者维护同一个项目,...

  • iOS-注解组件化(二)

    很早之前使用CTMediator做了组件化,在使用过程中有些不太方便的地方: Swift项目,底层使用OC的反射,...

  • iOS-组件化-(跳转+传参数)

    iOS开发中组件化之业务组件间通讯方式之路由[https://www.jianshu.com/p/862564d4...

网友评论

      本文标题:iOS-组件化

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