iOS runtime實戰(zhàn)應用:成員變量和屬性

前言

在開始之前建議先閱讀iOS runtime的基礎理解篇:iOS內(nèi)功篇:runtime

有筒子在面試的時候肥矢,遇到這樣一個問題:“你知道成員變量的本質(zhì)是什么嗎?”叠洗,筒子立馬懵逼了甘改,成員變量的本質(zhì)旅东?成員變量就是成員變量啊,平時只管用十艾,還有什么更深層的含義抵代?本文著重介紹runtime中成員變量和屬性的定義和使用。

名詞解析

成員變量

1忘嫉、定義:
Ivar: 實例變量類型荤牍,是一個指向objc_ivar結(jié)構(gòu)體的指針

typedef struct objc_ivar *Ivar;

2、操作函數(shù):

// 獲取所有成員變量
class_copyIvarList
// 獲取成員變量名
ivar_getName
// 獲取成員變量類型編碼
ivar_getTypeEncoding
// 獲取指定名稱的成員變量
class_getInstanceVariable
// 獲取某個對象成員變量的值
object_getIvar
// 設置某個對象成員變量的值
object_setIvar

3庆冕、使用實例:
Model的頭文件聲明如下:

    @interface Model : NSObject {
        NSString * _str1;
    }
    @property NSString * str2;
    @property (nonatomic, copy) NSDictionary * dict1;
    @end

獲取其成員變量:

    unsigned int outCount = 0;
    Ivar * ivars = class_copyIvarList([Model class], &outCount);
    for (unsigned int i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[i];
        const char * name = ivar_getName(ivar);
        const char * type = ivar_getTypeEncoding(ivar);
        NSLog(@"類型為 %s 的 %s ",type, name);
    }
    free(ivars);

打印結(jié)果:

runtimeIvar[602:16885] 類型為 @"NSString" 的 _str1 
runtimeIvar[602:16885] 類型為 @"NSString" 的 _str2 
runtimeIvar[602:16885] 類型為 @"NSDictionary" 的 _dict1 

屬性

1参淫、定義:
objc_property_t:聲明的屬性的類型,是一個指向objc_property結(jié)構(gòu)體的指針

typedef struct objc_property *objc_property_t;

2愧杯、操作函數(shù):

// 獲取所有屬性
class_copyPropertyList

說明:使用class_copyPropertyList并不會獲取無@property聲明的成員變量

// 獲取屬性名
property_getName
// 獲取屬性特性描述字符串
property_getAttributes
// 獲取所有屬性特性
property_copyAttributeList

說明:
property_getAttributes函數(shù)返回objc_property_attribute_t結(jié)構(gòu)體列表涎才,objc_property_attribute_t結(jié)構(gòu)體包含name和value,常用的屬性如下:

屬性類型  name值:T  value:變化
編碼類型  name值:C(copy) &(strong) W(weak) 空(assign) 等 value:無
非/原子性 name值:空(atomic) N(Nonatomic)  value:無
變量名稱  name值:V  value:變化

使用property_getAttributes獲得的描述是property_copyAttributeList能獲取到的所有的name和value的總體描述力九,如 T@"NSDictionary",C,N,V_dict1

3耍铜、使用實例:

    unsigned int outCount = 0;
    objc_property_t * properties = class_copyPropertyList([Model class], &outCount);
    for (unsigned int i = 0; i < outCount; i ++) {
        objc_property_t property = properties[i];
        //屬性名
        const char * name = property_getName(property);
        //屬性描述
        const char * propertyAttr = property_getAttributes(property);
        NSLog(@"屬性描述為 %s 的 %s ", propertyAttr, name);
        
        //屬性的特性
        unsigned int attrCount = 0;
        objc_property_attribute_t * attrs = property_copyAttributeList(property, &attrCount);
        for (unsigned int j = 0; j < attrCount; j ++) {
            objc_property_attribute_t attr = attrs[j];
            const char * name = attr.name;
            const char * value = attr.value;
            NSLog(@"屬性的描述:%s 值:%s", name, value);
        }
        free(attrs);
        NSLog(@"\n");
    }
    free(properties);

打印結(jié)果:

runtimeIvar[661:27041] 屬性描述為 T@"NSString",&,V_str2 的 str2 
runtimeIvar[661:27041] 屬性的描述:T 值:@"NSString"
runtimeIvar[661:27041] 屬性的描述:& 值:
runtimeIvar[661:27041] 屬性的描述:V 值:_str2
runtimeIvar[661:27041] 
runtimeIvar[661:27041] 屬性描述為 T@"NSDictionary",C,N,V_dict1 的 dict1 
runtimeIvar[661:27041] 屬性的描述:T 值:@"NSDictionary"
runtimeIvar[661:27041] 屬性的描述:C 值:
runtimeIvar[661:27041] 屬性的描述:N 值:
runtimeIvar[661:27041] 屬性的描述:V 值:_dict1
runtimeIvar[661:27041] 

應用實例

1、Json到Model的轉(zhuǎn)化

在開發(fā)中相信最常用的就是接口數(shù)據(jù)需要轉(zhuǎn)化成Model了(當然如果你是直接從Dict取值的話跌前。棕兼。。)抵乓,很多開發(fā)者也都使用著名的第三方庫如JsonModel伴挚、Mantle或MJExtension等,如果只用而不知其所以然灾炭,那真和“搬磚”沒啥區(qū)別了茎芋,下面我們使用runtime去解析json來給Model賦值。

原理描述:用runtime提供的函數(shù)遍歷Model自身所有屬性蜈出,如果屬性在json中有對應的值田弥,則將其賦值。
核心方法:在NSObject的分類中添加方法:

- (instancetype)initWithDict:(NSDictionary *)dict {
    
    if (self = [self init]) {
        //(1)獲取類的屬性及屬性對應的類型
        NSMutableArray * keys = [NSMutableArray array];
        NSMutableArray * attributes = [NSMutableArray array];
        /*
         * 例子
         * name = value3 attribute = T@"NSString",C,N,V_value3
         * name = value4 attribute = T^i,N,V_value4
         */
        unsigned int outCount;
        objc_property_t * properties = class_copyPropertyList([self class], &outCount);
        for (int i = 0; i < outCount; i ++) {
            objc_property_t property = properties[i];
            //通過property_getName函數(shù)獲得屬性的名字
            NSString * propertyName = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
            [keys addObject:propertyName];
            //通過property_getAttributes函數(shù)可以獲得屬性的名字和@encode編碼
            NSString * propertyAttribute = [NSString stringWithCString:property_getAttributes(property) encoding:NSUTF8StringEncoding];
            [attributes addObject:propertyAttribute];
        }
        //立即釋放properties指向的內(nèi)存
        free(properties);
        
        //(2)根據(jù)類型給屬性賦值
        for (NSString * key in keys) {
            if ([dict valueForKey:key] == nil) continue;
            [self setValue:[dict valueForKey:key] forKey:key];
        }
    }
    return self;

}

讀者可以進一步思考:
1铡原、如何識別基本數(shù)據(jù)類型的屬性并處理
2偷厦、空(nil,null)值的處理
3燕刻、json中嵌套json(Dict或Array)的處理
嘗試解決以上問題只泼,你也能寫出屬于自己的功能完備的Json轉(zhuǎn)Model庫。

2卵洗、快速歸檔

有時候我們要對一些信息進行歸檔请唱,如用戶信息類UserInfo,這將需要重寫initWithCoder和encodeWithCoder方法,并對每個屬性進行encode和decode操作籍滴。那么問題來了:當屬性只有幾個的時候可以輕松寫完酪夷,如果有幾十個屬性呢榴啸?那不得寫到天荒地老孽惰?。鸥印。勋功。

原理描述:用runtime提供的函數(shù)遍歷Model自身所有屬性,并對屬性進行encode和decode操作库说。
核心方法:在Model的基類中重寫方法:

- (id)initWithCoder:(NSCoder *)aDecoder {
    if (self = [super init]) {
        unsigned int outCount;
        Ivar * ivars = class_copyIvarList([self class], &outCount);
        for (int i = 0; i < outCount; i ++) {
            Ivar ivar = ivars[i];
            NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
            [self setValue:[aDecoder decodeObjectForKey:key] forKey:key];
        }
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)aCoder {
    unsigned int outCount;
    Ivar * ivars = class_copyIvarList([self class], &outCount);
    for (int i = 0; i < outCount; i ++) {
        Ivar ivar = ivars[i];
        NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
        [aCoder encodeObject:[self valueForKey:key] forKey:key];
    }
}

3狂鞋、訪問私有變量

我們知道,OC中沒有真正意義上的私有變量和方法潜的,要讓成員變量私有骚揍,要放在m文件中聲明,不對外暴露啰挪。如果我們知道這個成員變量的名稱信不,可以通過runtime獲取成員變量,再通過getIvar來獲取它的值亡呵。
方法:

    Ivar ivar = class_getInstanceVariable([Model class], "_str1");
    NSString * str1 = object_getIvar(model, ivar);

歡迎大家交流探討抽活。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市锰什,隨后出現(xiàn)的幾起案子下硕,更是在濱河造成了極大的恐慌,老刑警劉巖汁胆,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件梭姓,死亡現(xiàn)場離奇詭異,居然都是意外死亡嫩码,警方通過查閱死者的電腦和手機糊昙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谢谦,“玉大人释牺,你說我怎么就攤上這事』赝欤” “怎么了没咙?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長千劈。 經(jīng)常有香客問我祭刚,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任涡驮,我火速辦了婚禮暗甥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘捉捅。我一直安慰自己撤防,他們只是感情好,可當我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布棒口。 她就那樣靜靜地躺著寄月,像睡著了一般。 火紅的嫁衣襯著肌膚如雪无牵。 梳的紋絲不亂的頭發(fā)上漾肮,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天,我揣著相機與錄音茎毁,去河邊找鬼克懊。 笑死,一個胖子當著我的面吹牛七蜘,可吹牛的內(nèi)容都是我干的谭溉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼崔梗,長吁一口氣:“原來是場噩夢啊……” “哼夜只!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蒜魄,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤扔亥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后谈为,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體旅挤,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年伞鲫,在試婚紗的時候發(fā)現(xiàn)自己被綠了粘茄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡秕脓,死狀恐怖柒瓣,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吠架,我是刑警寧澤芙贫,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站傍药,受9級特大地震影響磺平,放射性物質(zhì)發(fā)生泄漏魂仍。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一拣挪、第九天 我趴在偏房一處隱蔽的房頂上張望擦酌。 院中可真熱鬧,春花似錦菠劝、人聲如沸赊舶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽锯岖。三九已至介袜,卻和暖如春甫何,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背遇伞。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工辙喂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鸠珠。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓巍耗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渐排。 傳聞我的和親對象是個殘疾皇子炬太,可洞房花燭夜當晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 對于從事 iOS 開發(fā)人員來說,所有的人都會答出【runtime 是運行時】什么情況下用runtime?大部分人能...
    夢夜繁星閱讀 3,721評論 7 64
  • 地闊天高驯耻, 川深水長亲族, 原野靜穆, 有塵土飛揚可缚。 理理歸囊霎迫, 整整衣裳, 慢一慢匆匆的腳步啊帘靡, 前面就是久別的村莊...
    高湛明閱讀 326評論 2 2
  • 文/阿良 她是那樣的大大咧咧知给,一半憂傷一半明媚的女生。 中考完的那段日子描姚,開始第一段戀情涩赢。她整日泡在吉他教室里,練...
    簫良溪閱讀 327評論 0 0
  • 1.關(guān)于圣誕節(jié)的那些事 2.孩子屬于的類型 大寶屬于力量型和敏感型轩勘,二寶屬于溫順型筒扒? 3.關(guān)注孩子的敏感期 4.和...
    然然11閱讀 365評論 0 0
  • typedef用來定義類型別名,c/c++里都有赃阀,屬于語言的一個特性霎肯,和mfc無關(guān)比如 typeof擎颖,我所知道的是...
    hehtao閱讀 676評論 0 3