iOS之Swift組件化方案(一)

參考資料:iOS組件化探索

未命名.001.jpeg

未命名.002.jpeg
//
//  ViewController.swift
//  SwiftDemo
//
//  Created by Leo on 2020/1/3.
//  Copyright ? 2020 Leo. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        //url方案
        //Mediator.sharedInstance.openURL(url: "sd://goToDetail", param: "xx" as AnyObject)
        // runtime方案
        let vc = Mediator.sharedInstance.getDetailViewController(nextID: "xx")
        self.navigationController?.pushViewController(vc!, animated: true)
    }
}

//
//  NextViewController.swift
//  SwiftDemo
//
//  Created by Leo on 2020/6/22.
//  Copyright ? 2020 Leo. All rights reserved.
//

import UIKit

class NextViewController: UIViewController {

    var nextID:String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    convenience init(nextID:String) {
        self.init()
        self.nextID = nextID
    }
}

//
//  Mediator.swift
//  SwiftDemo
//
//  Created by Leo on 2020/6/22.
//  Copyright ? 2020 Leo. All rights reserved.
//

import UIKit

let kDetailComponent:String = "DetailComponent"

class Mediator: NSObject {
    static let sharedInstance = Mediator()
    private var registerCache:Dictionary<String,(AnyObject)->()> = [:]
    private override init() {
        super.init()
    }
    // URL方案
    func register(url:String,callBack:@escaping (AnyObject)->()){
        registerCache[url] = callBack
    }
    
    func openURL(url:String,param:AnyObject){
        let callBack = registerCache[url]
        if let blk = callBack {
            blk(param);
        }
    }
    
    // 運(yùn)行時(shí)方案
    @objc func getDetailViewController(nextID:String) -> UIViewController?{
        if let m = method(cls: kDetailComponent, selName: "detailComponent_getDetailViewControllerWithNextID:"){
            return m(nextID) as? UIViewController
        }
        return nil
    }
    
    func method(cls:String,selName:String) -> ((Any?) -> Any)?{
        let selector = NSSelectorFromString(selName)
        let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String
        // 拼接類名的完整格式,即namespace.類名,vcName即控制器的類名
        let clsName = namespace + "." + "DetailComponent"
        return extractMethodFrom(owner: NSClassFromString(clsName)!, selector: selector)
    }
    
    func extractMethodFrom(owner: AnyObject, selector: Selector) -> ((Any?) -> Any)? {
        let method: Method?
        if owner is AnyClass {
           method = class_getClassMethod(owner as? AnyClass, selector)
        } else {
           print(type(of: owner))
           method = class_getInstanceMethod(type(of: owner), selector)
        }
        if let one = method {
           let implementation = method_getImplementation(one)
           typealias Function = @convention(c) (AnyObject, Selector, Any?) -> Any
           let function = unsafeBitCast(implementation, to: Function.self)
           return { userinfo in function(owner, selector, userinfo) }
        } else {
           return nil
        }
    }
}

//
//  DetailComponent.swift
//  SwiftDemo
//
//  Created by Leo on 2020/6/22.
//  Copyright ? 2020 Leo. All rights reserved.
//

import UIKit

class DetailComponent: NSObject {
    
    // URL方案
    static func initComponent() -> Void{
        Mediator.sharedInstance.register(url: "sd://goToDetail") { (obj) in
            let str = obj as! String
            let vc = NextViewController.init(nextID: str)
            (UIApplication.shared.keyWindow?.rootViewController as? UINavigationController)?.pushViewController(vc, animated: true)
        }
    }
    
    // 運(yùn)行時(shí)方案
    @objc(detailComponent_getDetailViewControllerWithNextID:)
    static func detailComponent_getDetailViewController(id:String) -> UIViewController{
        let vc = NextViewController.init(nextID: id)
        return vc
    }
    
    func get_class_copyMethodList() -> [String]{
        var outCount:UInt32
        outCount = 0
        let methods:UnsafeMutablePointer<objc_property_t>! =  class_copyMethodList(self.classForCoder, &outCount)
        let count:Int = Int(outCount);
        var names:[String] = [String]()
        for i in 0...(count-1) {
            
            let aMet: objc_property_t = methods[i]
            
            if let methodName:String = String(utf8String: property_getName(aMet)){
                names.append(methodName)
            }
        }
        return names
    }
    
}
//
//  AppDelegate.swift
//  SwiftDemo
//
//  Created by Leo on 2020/1/3.
//  Copyright ? 2020 Leo. All rights reserved.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

     var isLandscape = false

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // URL方案需要在程序啟動(dòng)時(shí) 注冊(cè)相應(yīng)方法以及閉包
        DetailComponent.initComponent()
        return true
    }
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        if isLandscape == true{
            return [.portrait,.landscapeLeft,.landscapeRight]
        }else{
            return .portrait
        }
    }

    // MARK: UISceneSession Lifecycle

    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // Called when a new scene session is being created.
        // Use this method to select a configuration to create the new scene with.
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // Called when the user discards a scene session.
        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末功炮,一起剝皮案震驚了整個(gè)濱河市室囊,隨后出現(xiàn)的幾起案子杭隙,更是在濱河造成了極大的恐慌诉儒,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矾飞,死亡現(xiàn)場(chǎng)離奇詭異筒饰,居然都是意外死亡械姻,警方通過查閱死者的電腦和手機(jī)悍引,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門恩脂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帽氓,“玉大人趣斤,你說我怎么就攤上這事±栊荩” “怎么了浓领?”我有些...
    開封第一講書人閱讀 152,671評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長势腮。 經(jīng)常有香客問我联贩,道長,這世上最難降的妖魔是什么捎拯? 我笑而不...
    開封第一講書人閱讀 55,252評(píng)論 1 279
  • 正文 為了忘掉前任泪幌,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祸泪。我一直安慰自己吗浩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,253評(píng)論 5 371
  • 文/花漫 我一把揭開白布没隘。 她就那樣靜靜地躺著懂扼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪右蒲。 梳的紋絲不亂的頭發(fā)上阀湿,一...
    開封第一講書人閱讀 49,031評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音瑰妄,去河邊找鬼陷嘴。 笑死,一個(gè)胖子當(dāng)著我的面吹牛间坐,可吹牛的內(nèi)容都是我干的罩旋。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼眶诈,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼涨醋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起逝撬,我...
    開封第一講書人閱讀 36,973評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤浴骂,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宪潮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體溯警,經(jīng)...
    沈念sama閱讀 43,466評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,937評(píng)論 2 323
  • 正文 我和宋清朗相戀三年狡相,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了梯轻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,039評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡尽棕,死狀恐怖喳挑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滔悉,我是刑警寧澤伊诵,帶...
    沈念sama閱讀 33,701評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站回官,受9級(jí)特大地震影響曹宴,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜歉提,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,254評(píng)論 3 307
  • 文/蒙蒙 一笛坦、第九天 我趴在偏房一處隱蔽的房頂上張望区转。 院中可真熱鬧,春花似錦版扩、人聲如沸蜗帜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厅缺。三九已至,卻和暖如春宴偿,著一層夾襖步出監(jiān)牢的瞬間湘捎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工窄刘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窥妇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,497評(píng)論 2 354
  • 正文 我出身青樓娩践,卻偏偏與公主長得像活翩,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子翻伺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,786評(píng)論 2 345