iOS推送從任意頁面跳轉(zhuǎn)任意頁面

其實(shí)這篇文章,是上篇文章Runtime的應(yīng)用部分的展開,從任意頁面跳轉(zhuǎn)任意頁面這塊主要不是Runtime的知識點(diǎn),所以沒在上篇文章中進(jìn)行展開。
首先新建一個(gè)工程,并在storyboard上面拖出來一個(gè)UITabBarController,加上兩個(gè)UINavgationController,再加上四個(gè)UIViewController,具體布局如圖:


storyboard布局.png

然后再建四個(gè)UIViewController子類,并綁定到Storyboard上面的ViewController上面,并設(shè)置Storyboard ID


新建VC子類.png

然后storyboard的每個(gè)ViewController上面添加兩個(gè)Label,并綁定到代碼文件里面。然后給暖色One和暗色One的View添加點(diǎn)擊一個(gè)手勢,把點(diǎn)擊事件綁定到代碼文件里面,我的屬性事件命名就隨意了。
綁定.png

然后在手勢點(diǎn)擊事件方法,寫上跳轉(zhuǎn)到Two頁面的代碼。
下面我們新建五個(gè)DataModel,一個(gè)PushModel,四個(gè)相應(yīng)的VC的DataModel,我就取名WarmOneDataModel ,WarmTwoDataModel , DeadOneDataModel,DeadTwoDataModel(命名隨意)

Model.png

然后在PushModel里面寫上四個(gè)屬性,類型則是另外四個(gè)Model

PushModel.png

四個(gè)VC的Model里面的代碼是一樣的(主要是省事,實(shí)際項(xiàng)目里面肯定不是這樣的了)


dataModel.png

然后在幾個(gè)對應(yīng)的ViewController寫上對應(yīng)的DataModel類型的屬性,再把topLabelStr和BottomLabelStr取出來賦值給兩個(gè)Lable。

賦值.png

目前前期準(zhǔn)備工作已經(jīng)完成了,下面需要在AppDelegate里面開始處理推送過來的信息,已經(jīng)跳轉(zhuǎn),傳值邏輯了。
我新建了一個(gè)SwiftRunTimeTool 類

class func checkClassPerporty(object : AnyClass , propertyStr: String) -> Bool{
        var count : UInt32 = 0
        let propertys = class_copyPropertyList(object, &count)
        for index in 0 ..< Int(count){
            let name = property_getName(propertys?[index])
            if let propertyName = String.init(validatingUTF8: name!){
                if propertyName == propertyStr{
                    return true
                }
            }
        }
        return false
    }

利用Runtime做KVC之前的保護(hù)
關(guān)于push過來的信息格式,需要和后臺進(jìn)行對接好,不然錯(cuò)誤的key,name,會導(dǎo)致取不到想要的值

 // let params = ["class" : "填入需要跳轉(zhuǎn)VC名字字符串" , "property" : [ "跳入VC需要用到的數(shù)據(jù)Model":["數(shù)據(jù)Model屬性字符串" : "數(shù)據(jù)Model屬性值"] ] , "modelName" : "數(shù)據(jù)Model在pushModel中的名字"] as [String : Any]
 //模擬推送過來的信息
    func setPushParams() ->[String : AnyObject]{
        let params = ["class" : "WarmColorOneViewController" , "property" : [ "WarmOneDataModel":["topLabelStr" : "我是推送過來的信息" , "bottomLabelStr" : "我也是推送過來的信息"] ] , "modelName" : "warmOneModel"] as [String : Any]
        return params as [String : AnyObject]
    }

然后再寫一個(gè)方法

//處理推送信息進(jìn)行跳轉(zhuǎn)傳值方法
    func conductPushParams(params : [String : AnyObject]){
        
    }

接下來在本地新建一個(gè)plist文件,新建四個(gè)item,key是四個(gè)類的類名字符串,value是對應(yīng)的Storyboard ID

Storyboard ID.png
    //處理推送信息進(jìn)行跳轉(zhuǎn)傳值方法
    func conductPushParams(params : [String : AnyObject]){
        //先檢查推送過來的字典里面Class存不存在
        guard let className = params["class"] as? String else{
            print("參數(shù)類名不存在")
            return
        }
        //讀取Plist文件
        let filePath = Bundle.main.path(forResource: "VCStoryboardIDList", ofType: "plist") ?? ""
        let vcDic : NSDictionary = NSDictionary(contentsOfFile: filePath) ?? NSDictionary()
        
        //判斷plist文件里面是否含有目標(biāo)VC的Storyboard ID
        if let vcID = vcDic[className] {
            
            guard let nameSpace = Bundle.main.infoDictionary!["CFBundleExecutable"] else {
                print("命名空間不存在")
                return
            }
            //如果VC是與storyboard關(guān)聯(lián)的通過下面的語句創(chuàng)建VC對象
            let clsVC = UIStoryboard.init(name: "Main", bundle: nil).instantiateViewController(withIdentifier:  vcID as! String)
            
            setPushModelInfo(clsVC: clsVC, params: params, nameSpace: nameSpace as! String)
        }else{

            guard let nameSpace = Bundle.main.infoDictionary!["CFBundleExecutable"] else {
                print("命名空間不存在")
                return
            }
            //如果不是storyboard綁定的UIViewController 則通過這種方式創(chuàng)建其對象
            let vcClassTemp : AnyClass? = NSClassFromString((nameSpace as! String) + "." + className)
            guard let vcClsType = vcClassTemp as? UIViewController.Type else{
                print("無法轉(zhuǎn)換為UIViewController類型")
                return
            }
            //創(chuàng)建對應(yīng)View Controller 對象
            let clsVC = vcClsType.init()
            setPushModelInfo(clsVC: clsVC, params: params, nameSpace: nameSpace as! String)
        }
    }
    //因?yàn)閏onductPushParams里面if else里面重復(fù)代碼挺多,所以我抽離出來重新寫了一個(gè)方法
    func setPushModelInfo(clsVC : UIViewController , params : [String : Any] , nameSpace : String){
        
        //創(chuàng)建PushModel 對象
        let pushModel = PushModel()
        
        //根據(jù) params["property"]里面的dataModel名字字符串,創(chuàng)建其對象,首先獲取命名空間字符串
        guard let propertyDic = params["property"] as? [String : Any] else{
            print("property信息不存在")
            return
        }
        for key in propertyDic.keys{
            //然后NSClassFromString獲取到DataModel 的Class
            let modelClassTemp : AnyClass? = NSClassFromString((nameSpace) + "." + key)
            //然后判斷有沒有獲取成功
            guard let modleClsType = modelClassTemp as? NSObject.Type else{
                return
            }
            //根據(jù)推送過來的信息對dataModel進(jìn)行賦值
            guard let modelDic = propertyDic[key] as? [String : String]else{
                print("model信息不存在")
                return
            }
            let dataModel = modleClsType.init()
            for modelKey in modelDic.keys{
                //首先確定model里面有相應(yīng)的屬性
                if SwiftRunTimeTool.checkClassPerporty(object: object_getClass(dataModel), propertyStr: modelKey){
                    dataModel.setValue(modelDic[modelKey]! as String, forKey: modelKey)
                }
            }
            //再根據(jù)推送過來dataModel再pushModel里面的名字字符串,對pushModel進(jìn)行賦值
            guard let modelName = params["modelName"] as? String else{
                print("modelName不存在")
                return
            }
            //確保pushModel里面有對應(yīng)名字的屬性
            if SwiftRunTimeTool.checkClassPerporty(object: object_getClass(pushModel), propertyStr: modelName){
                pushModel.setValue(dataModel, forKey: modelName)
            }
        }
        //確保跳轉(zhuǎn)的VC里面有pushModel屬性
        if SwiftRunTimeTool.checkClassPerporty(object: object_getClass(clsVC), propertyStr: "pushModel"){
            clsVC.setValue(pushModel, forKey: "pushModel")
        }
        
        //找UITabBarController
        guard let tabBarController = self.window?.rootViewController as?UITabBarController else {
            print("UITabBarController找不到")
            return
        }
        //找UINavigationController
        guard let navigationController = tabBarController.viewControllers?[tabBarController.selectedIndex] as? UINavigationController else {
            print("navigationController找不到")
            return
        }
        //如果有Present上出的頁面,可以通過 tabBarController調(diào)用Dismiss
//        tabBarController.dismiss(animated: true, completion: nil)
        
        clsVC.hidesBottomBarWhenPushed = true
        navigationController.pushViewController(clsVC, animated: true)
    }

好了,至此算是結(jié)束了,如果和后臺對接好,理論上可以進(jìn)行任意頁面的跳轉(zhuǎn)。。。最終Demo在這里:最終Demo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容