用Runtime做點(diǎn)什么(一)

前言

網(wǎng)上關(guān)于runtime的教程都有很多,但時(shí)很多大部分都是講解原理,并沒(méi)有實(shí)際運(yùn)用runtime寫(xiě)一些東西,所以很難讓人理解。我覺(jué)得要是有實(shí)際的運(yùn)用的話,應(yīng)該能夠更深刻的理解。

先看一個(gè)效果

圖-1.png

圖-1 是我寫(xiě)的代碼,我們假裝json時(shí)從網(wǎng)絡(luò)上取來(lái)的數(shù)據(jù) , 然后把json的值賦給ViewController的model , model 是通過(guò)ModelCompatible這個(gè)協(xié)議得來(lái)的 ,如圖-2


圖-2

ModelCompatible有一個(gè)屬性和一個(gè)方法,但凡有繼承來(lái)這個(gè)屬性的類(lèi)(ps : 只有類(lèi),雖然swift中的enum struct也能繼承協(xié)議。但是我們這個(gè)協(xié)議的后面是繼承了一個(gè)class的關(guān)鍵字,表示這個(gè)協(xié)議就只能被類(lèi)繼承了)

這個(gè)json里面的key值都和ViewController的屬性相同,當(dāng)把json賦值給model的時(shí)候,就會(huì)相應(yīng)地改變ViewController的里面的屬性的值,


圖-3
圖-4

這里打印了它的id,id也自動(dòng)也被自動(dòng)賦了值
這樣寫(xiě)的好處是,能大大減少我們的代碼,而且使得代碼的可讀性更高。

思路

先通過(guò)runtime遍歷一個(gè)的類(lèi)的所有屬性(不包括父類(lèi)),然后和model里面的key比較,如果這個(gè)屬性和key一樣,在比較這個(gè)屬性的類(lèi)型,如果是String , Int , float 之類(lèi)的,就把它們的json的key對(duì)應(yīng)的值直接賦值給ViewController的屬性的值。使用下面這個(gè)方法賦值。

setValue(value: Any?, forKey: String)

如果不是上面那個(gè)類(lèi)型,那么就賦值給它的text的路徑的屬性下(因?yàn)樗械膌abel , textField 都有text這個(gè)屬性),使用下面的代碼

setValue(value: Any? , forKeyPath:  String)

如果這個(gè)屬性沒(méi)有text的屬性會(huì)怎么辦,會(huì)崩潰。所以,前面使用了協(xié)議的方法,讓擁有了這個(gè)協(xié)議的viewcontroller才會(huì)擁有這個(gè)runtime的小技巧。如果是擴(kuò)展到所有UIViewController及它的子類(lèi)下,就有可能出現(xiàn)一些不可控的崩潰。

最后擴(kuò)展下UImageView給它添加text的屬性。

圖-5

所有json要映射到UIViewController里面的視圖屬性上來(lái)顯示,一般都是label, textfield , imageView (imageview是沒(méi)有text的,所以要擴(kuò)展一個(gè)) 。所以下面的代碼直接ctrl + c 就可以用了。但是,最好是懂runtime的前提下去使用。這些主要是分享給那些懂runtime,但是不知道怎么在項(xiàng)目里運(yùn)用的人。不懂runtime的要先看懂別人的runtime的文章在來(lái)看這個(gè)。


import UIKit

extension NSObject {
    
    var allKeys : [String] {
        
        var returnArr = [String]()
        
        var outCount : UInt32 = 0
        let members = class_copyPropertyList(self.classForCoder, &outCount)
        
        for i in 0..<numericCast(outCount) {
            
            autoreleasepool{
                
                let member = members![i]
                let property = property_getName(member)
                
                
                let propertyName = String.init(cString: property!)
                
                returnArr.append(propertyName)
            }
        }
        
        return returnArr
    }
    
}

public protocol ModelCompatible : class {
    var model : Any? {set get}
    func render()
}

fileprivate var modelkey : Void!
public extension ModelCompatible {
    
    public var model : Any? {
        get{
            return  objc_getAssociatedObject(self, &modelkey)
        }
        set{
            objc_setAssociatedObject(self, &modelkey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            //每次賦值model后就調(diào)用這個(gè)方法
            render()
        }
    }
    
    func render() {
        
            //因?yàn)橐玫絩untime , 所以要轉(zhuǎn)成OC的NSObject
            if let objself = self as? NSObject {
                
                var outCount : UInt32 = 0
                //我選擇用property而不是ivar,是因?yàn)閜roperty足夠用了
                let members = class_copyPropertyList(objself.classForCoder, &outCount)
                
                for i in 0..<numericCast(outCount) {
                    
                    autoreleasepool{
                        
                        let member = members![i]
                        let property = property_getName(member)
                        let attribute = property_getAttributes(member)
                        
                        //通過(guò)runtime獲取到了屬性名
                        let propertyName = String.init(cString: property!)
                        
                        //通過(guò)runtime獲取到了類(lèi)型名
                        let typeName     = String(cString: attribute!).components(separatedBy: ",").first as NSString!
                        let typeStr = typeName!.substring(from: 1)
                        
                        
                        //將模型轉(zhuǎn)為NSObject類(lèi) ,Dictionary也可以轉(zhuǎn)成NSObject
                        if let dic = self.model as? NSObject {
                            
                            
                            if dic.allKeys.contains(propertyName){
                                
                                if typeStr == "@\"NSString\"" || typeStr == "q" || typeStr == "d" || typeStr == "d"{
                                    //kvc賦值
                                    objself.setValue(dic.value(forKey: propertyName)!, forKey: propertyName)
                                    
                                }else{
                                    
                                    //kvc 賦值在一些類(lèi)屬性下的text屬性下 , 
                                    //如果這個(gè)類(lèi)沒(méi)有text,就會(huì)崩潰。
                                    objself.setValue(String(describing: dic.value(forKey: propertyName)!), forKeyPath: propertyName + ".text")
                                    
                                }
                            }
                        }
                    }
                }
                free(members)
            }
    }
}

extension UIImageView {
    var text: String {
        set{
            print("把獲取到的url:", newValue , "轉(zhuǎn)成圖片")
            /**
             比如: self.kf.setImage(with : url)
            */
        }
        get{
            return "沒(méi)有g(shù)et方法"
        }
    }
}

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

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,544評(píng)論 19 139
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫(kù)、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,195評(píng)論 4 61
  • *面試心聲:其實(shí)這些題本人都沒(méi)怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來(lái)就是把...
    Dove_iOS閱讀 27,604評(píng)論 30 472
  • CloudFormation 是AWS的一款管理服務(wù),用來(lái)集中式快速地創(chuàng)建AWS配套資源。 概念 模板 Cloud...
    azzgo閱讀 3,987評(píng)論 0 2
  • 自從開(kāi)始畫(huà)石頭畫(huà),覺(jué)得特別神奇。簡(jiǎn)單的圖案在石頭上就能很好看,畫(huà)的過(guò)程也特別心靜,很喜歡這種感覺(jué)。 端午假期回來(lái),...
    柚子酸溜溜閱讀 706評(píng)論 1 3

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