參考資料:iOS組件化探索
//
// 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.
}
}