Runtime梳理(二)

挖就挖底層.png

繼上《Runtime梳理(一)》

這一章分成四個部分進行學習:1. Runtime的特征 2. Runtime的Category 3.Runtime的歸檔 功能 4. Runtime的數(shù)據(jù)轉(zhuǎn)換

第一部分:Runtime的特征

直接舉例:

  • Gril類

// "Gril.h"
@interface Gril : NSObject
{
NSString * _occupation;
NSString * _nationality;
}
@property (copy, nonatomic) NSString * name;
@property (assign, nonatomic) NSUInteger age;

  • (NSDictionary *)allProperties;
  • (NSDictionary *)allvars;
  • (NSDictionary *)allmethods;

* ----
> 

// Gril.m

if TARGET_IPHONE_SIMULATOR

import <objc/objc-runtime.h>

else

import <objc/runtime.h>

import <objc/message.h>

endif

import "Gril.h"

@interface Gril () //
{
NSString * _liver;
}
@property (assign, nonatomic) double heigth;
@end


@implementation Gril
{
int _countA; // 注意這里哦
}

  • (NSDictionary *)allProperties
    {
    unsigned int count = 0;
    objc_property_t * properties = class_copyPropertyList([self class], &count);
    NSMutableDictionary * dict = [@{} mutableCopy];
    for (NSUInteger i = 0; i < count; i++)
    {
    // 名稱
    const char * propertyName = property_getName(properties[i]);
    NSString *name = [NSString stringWithUTF8String:propertyName];
    // 值
    id propertyValue = [self valueForKey:name];
    if (propertyValue) {
    dict[name] = propertyValue;
    }
    else
    {
    dict[name] = @"!waning; key:value != nil------allProperties";
    }
    }
    free(properties); // 去內(nèi)存
    return dict;
    }

* ----

  • (NSDictionary *)allvars
    {
    unsigned int count = 0;
    NSMutableDictionary * dict = [@{} mutableCopy];
    Ivar * ivars = class_copyIvarList([self class], &count);
    for (NSUInteger i = 0; i < count; i++)
    {
    const char * varName = ivar_getName(ivars[i]);
    NSString *name = [NSString stringWithUTF8String:varName];
    id varValue = [self valueForKey:name];
    if (varValue) {
    dict[name] = varValue;
    }
    else
    {
    dict[name] = @"!waning畅形; key:value != nil------allvars";
    }
    }
    free(ivars);
    return dict;
    }

* ----

  • (NSDictionary *)allmethods
    {
    unsigned int count = 0;
    NSMutableDictionary * dict = [@{} mutableCopy];
    Method * methods = class_copyMethodList([self class], &count);
    for (NSUInteger i = 0; i < count; i++)
    {
    SEL methodSEL = method_getName(methods[i]);
    const char * methodName = sel_getName(methodSEL);
    NSString * name = [NSString stringWithUTF8String:methodName];
    int arguments = method_getNumberOfArguments(methods[i]);
    dict[name] = @(arguments-2);
    }
    free(methods);
    return dict;
    }

> 大家看到什么?.m文件中
變量什么 私有變量榕吼? 匿名擴展相關(guān)知識自己補充了继低,這里不贅述了

我們來驗證一下我們獲得了什么吧竹宋?
> ````
// 首先 添加對象
    Gril * grilTeacher = [[Gril alloc] init];
    grilTeacher.name = @"女教師";
    grilTeacher.age = 26;
    [grilTeacher setValue:@"教師" forKey:@"occupation"];
  1. 下面獲得property
 NSDictionary * dict = [grilTeacher allProperties];
    NSLog(@"%@", dict);

打印結(jié)果:
2016-04-09 19:55:50.614 RuntimeLine[2305:195629] { age = 26; heigth = 0; //這個是.m文件屬性哦劳澄,獲取了。蜈七。秒拔。 name = "\U5973\U6559\U5e08"; }
heigth? 不意外嗎?飒硅!

  1. 獲得Ivar
NSDictionary * dict = [grilTeacher allvars];
    NSLog(@"%@", dict);

打印結(jié)果:
2016-04-09 20:01:41.397 RuntimeLine[2349:199801] { "_age" = 26; "_countA" = 0;//這是....獲取了砂缩。。狡相。 "_heigth" = 0; "_liver" = "!waning\Uff1b key:value != nil------allvars"; "_name" = "\U5973\U6559\U5e08"; "_nationality" = "!waning\Uff1b key:value != nil------allvars"; "_occupation" = "\U6559\U5e08"; }
countA 也獲取了梯轻,還不意外?尽棕!
還順便理解了propertyIvar區(qū)別吧

  1. 獲取Methods
    NSDictionary * dict = [grilTeacher allmethods];
    NSLog(@"%@", dict);

打印結(jié)果:
2016-04-09 20:09:39.363 RuntimeLine[2372:204392] { ".cxx_destruct" = 0;// 這個方法這在ARC的環(huán)境下才會被調(diào)用 銷毀意思 age = 0; allProperties = 0; //++ allmethods = 0; //++ allvars = 0; --- heigth = 0; name = 0; "setAge:" = 1; ???? "setHeigth:" = 1; ??? "setName:" = 1; ??? }
很牛逼吧,set get方法 內(nèi)存管理機制 彬伦?滔悉??還不很意外了嗎单绑?回官??搂橙!

不能做的都做了歉提, 萬能吧,還真是区转,

這就是Runtime苔巨?Objective-C objc 的根基所在


第二部分:Runtime的Category

  • 創(chuàng)建Gril+Hiee

// Gril+Hiee.h

import "Gril.h"

typedef void (^codingCallBack)();
@interface Gril (Hiee)
@property (strong, nonatomic) NSNumber * associatedBust; //x胸圍?废离?呵呵
@property (copy, nonatomic) codingCallBack associatedCallBack; // 寫代碼 哈哈
@end


> ````
// Gril+Hiee.m
#import "Gril+Hiee.h"
#if TARGET_IPHONE_SIMULATOR
#import <objc/objc-runtime.h>
#else
#import <objc/runtime.h>
#import <objc/message.h>
#endif
@implementation Gril (Hiee)
- (void)setAssociatedBust:(NSNumber *)bust
{
    // 關(guān)聯(lián)對象 objc_association_retain_nonatomc
    objc_setAssociatedObject(self, @selector(associatedBust), bust, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)associatedBust
{
    // 獲取關(guān)聯(lián)
    return objc_getAssociatedObject(self, @selector(associatedBust));
}
- (void)setAssociatedCallBack:(codingCallBack)callBack
{
    objc_setAssociatedObject(self, @selector(associatedCallBack), callBack, OBJC_ASSOCIATION_COPY_NONATOMIC);
}
- (codingCallBack)associatedCallBack
{
    return objc_getAssociatedObject(self, @selector(associatedCallBack));
}

驗證一下在category中是否有效侄泽??蜻韭?
準備:

Gril * grilTeacher = [[Gril alloc] init];
grilTeacher.name = @"女教師";
grilTeacher.age = 26;
[grilTeacher setValue:@"教師" forKey:@"occupation"];
grilTeacher.associatedBust = @(120); // 豪大大的
grilTeacher.associatedCallBack = ^(){
NSLog(@"當男友出軌的時候悼尾,趕緊回來找bug,一定是代碼沒寫好肖方,導致的闺魏。。俯画。析桥。");
};
grilTeacher.associatedCallBack();
NSDictionary * propertyDict = [grilTeacher allProperties];
NSDictionary * lvarDict = [grilTeacher allvars];
NSDictionary * methodDict = [grilTeacher allmethods];
NSLog(@"%@", propertyDict);
NSLog(@"%@", lvarDict);
NSLog(@"%@", methodDict);


輸出結(jié)果呢?
`
2016-04-09 21:22:50.685 RuntimeLine[2959:242125] 當男友出軌的時候,趕緊回來找bug烹骨,一定是代碼沒寫好翻伺,導致的。沮焕。吨岭。。
2016-04-09 21:22:50.687 RuntimeLine[2959:242125] {
    age = 26;
    associatedBust = 120;  峦树、辣辫、、魁巩、???有效
    associatedCallBack = "<__NSGlobalBlock__: 0x1000030e0>"; 急灭、、谷遂、葬馋、???有效
    heigth = 0;
    name = "\U5973\U6559\U5e08";
}
2016-04-09 21:22:50.688 RuntimeLine[2959:242125] {
    "_age" = 26;
    "_countA" = 0;
    "_heigth" = 0;
    "_liver" = "!waning\Uff1b key:value != nil------allvars";
    "_name" = "\U5973\U6559\U5e08";
    "_nationality" = "!waning\Uff1b key:value != nil------allvars";
    "_occupation" = "\U6559\U5e08";
}
2016-04-09 21:22:50.688 RuntimeLine[2959:242125] {
    ".cxx_destruct" = 0;
    age = 0;
    allProperties = 0;
    allmethods = 0;
    allvars = 0;
    associatedBust = 0;
    associatedCallBack = 0;
    heigth = 0;
    name = 0;
    "setAge:" = 1;
    "setAssociatedBust:" = 1; 、肾扰、畴嘶、、集晚、???有效
    "setAssociatedCallBack:" = 1; 窗悯、、偷拔、蒋院、、???有效
    "setHeigth:" = 1;
    "setName:" = 1;
}
Program ended with exit code: 0
`
看到了嗎莲绰? 在`category`中也完全有效欺旧? 有點廢話?還有哦

###第三部分: Runtime的歸檔功能
> 大家知道:
1. 為了將應用數(shù)據(jù)存儲到硬盤中钉蒲,iOS提供基本的文件`API`切端、`Property List`序列化、`SQLite`顷啼、`CoreData`以及`NSCoding`踏枣。
2. 是類對象本身數(shù)據(jù)的寫入到本地文件。
我 們需要實現(xiàn)兩個方法: `encodeWithCoder`和`initWithEncoder`钙蒙。`encodeWithCoder`就是編碼茵瀑,`initWithCoder`就是解碼。 `encodeWithCoder`方法傳入的是一個`NSCoder`對象躬厌,實現(xiàn)的時候我們就可以調(diào)用`encodeObject马昨、encodeFloat竞帽、 encodeInt`等各種方法并通過指定鍵值進行編碼。

* 下面我們寫專業(yè)一點 歸檔嘛
> ````
// Gril.h
#import <Foundation/Foundation.h>
@interface Gril : NSObject <NSCoding>
@property (copy, nonatomic) NSString * occupation; // 專業(yè)
@property (copy, nonatomic) NSString * nationality;  // 國度
@property (copy, nonatomic) NSString * name;  // 名稱
@property (assign, nonatomic) NSUInteger age;  // 年齡
@end

// Gril.m

if TARGET_IPHONE_SIMULATOR

import <objc/objc-runtime.h>

else

import <objc/runtime.h>

import <objc/message.h>

endif

import "Gril.h"

@implementation Gril

  • (void)encodeWithCoder:(NSCoder *)aCoder
    {
    unsigned int count = 0;
    Ivar * ivars = class_copyIvarList([self class], &count);
    for (NSUInteger i = 0; i < count; i++)
    {
    const char * name = ivar_getName(ivars[i]);
    NSString * key = [NSString stringWithUTF8String:name];
    id value = [self valueForKey:key];
    [aCoder encodeObject:value forKey:key];
    }
    }
*----
  • (instancetype)initWithCoder:(NSCoder *)aDecoder
    {
    if (self = [super init]) {
    unsigned int count = 0;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (NSUInteger i = 0; i < count; i ++) {
    const char *name = ivar_getName(ivars[i]);
    NSString *key = [NSString stringWithUTF8String:name];
    id value = [aDecoder decodeObjectForKey:key];
    [self setValue:value forKey:key];
    }
    free(ivars);
    }
    return self;
    }
呵呵:枧酢屹篓!這樣就完成了。匙奴。堆巧。。

其實還有的...
###第四部分: runtime的數(shù)據(jù)轉(zhuǎn)換
> 反之泼菌,當服務器返回了大量數(shù)據(jù)谍肤,iOS端這邊接收后如何去轉(zhuǎn)換呢?在我們的項目中也用到過這些`json`轉(zhuǎn)成Model三方庫:MJExtention哗伯、YY荒揣。。焊刹。忘了系任,下面了解下runtime實現(xiàn)JSON和Model互轉(zhuǎn)。
* 還是用我們類Gril吧虐块, 我就喜歡用Gril來表達一下

> ````
// Gril.h
#import <Foundation/Foundation.h>
@interface Gril : NSObject 
@property (copy, nonatomic) NSString * occupation; // 專業(yè)
@property (copy, nonatomic) NSString * nationality;  // 國度
@property (copy, nonatomic) NSString * name;  // 名稱
@property (assign, nonatomic) NSUInteger age;  // 年齡
@end

// Gril.m

if TARGET_IPHONE_SIMULATOR

import <objc/objc-runtime.h>

else

import <objc/runtime.h>

import <objc/message.h>

endif

import "Gril.h"

@implementation Gril
/** 生成模型 */

  • (instancetype)initWithDictionary:(NSDictionary )dict
    {
    if (self = [super init]) {
    for (NSString * key in dict.allKeys) {
    id value = dict[key];
    SEL setter = [self propertySetterByKey:key];
    if (setter) {
    ((void(
    )(id, SEL, id))objc_msgSend)(self, setter, value);
    }
    }
    }
    return self;
    }

*----

> ````
/** 生成字典  */
- (NSDictionary *)covertToDictionary
{
    unsigned int count  = 0;
    objc_property_t *properties = class_copyPropertyList([self class], &count);
    if (count != 0) {
        NSMutableDictionary *dict = [@{} mutableCopy];
        for (NSUInteger i = 0; i < count; i++)
        {
            const void * propertyName = property_getName(properties[i]);
            NSString * name = [NSString stringWithUTF8String:propertyName];
            SEL getter = [self propertyGetterByKey:name];
            if (getter)
            {
                id value = ( (id(*)(id, SEL))objc_msgSend)(self, getter);
                if (value)
                {
                    dict[name] = value;
                }
                else
                {
                    dict[name] = @"!Waning: key--value != nil !";
                }
            }
        }
        free(properties);
        return dict;
    }
    free(properties);
    return nil;
}

*----

pragma mark -- private methods

/** setter方法 */

  • (SEL)propertySetterByKey:(NSString )key
    {
    // 首字母大寫 setAge
    NSString * propertySetterName = [NSString stringWithFormat:@"set%@:",key.capitalizedString];
    SEL setter = NSSelectorFromString(propertySetterName);
    if ([self respondsToSelector:setter]) {
    return setter;
    }
    return nil;
    }
    /
    * getter方法 */
  • (SEL)propertyGetterByKey:(NSString *)key
    {
    SEL getter = NSSelectorFromString(key);
    if ([self respondsToSelector:getter]) {
    return getter;
    }
    return nil;
    }

* 測試驗證:

> ````
NSDictionary *dict = @{
                           @"name" : @"萌萌",
                           @"age"  : @(26),
                           @"occupation" : @"教師",
                           @"nationality" : @"瑞典國"
                           };
    // 字典轉(zhuǎn)模型
    Gril * grilTeacher = [[Gril alloc] initWithDictionary:dict];
    NSLog(@"age:%d, name: %@, occupation: %@, nationality:%@",  (int)grilTeacher.age, grilTeacher.name, grilTeacher.occupation, grilTeacher.nationality);
    // 模型轉(zhuǎn)字典
    NSDictionary * modelDict = [grilTeacher covertToDictionary];
    NSLog(@"%@",modelDict);

我們來看一下打印的結(jié)果是否成功吧:

`
2016-04-10 01:25:38.836 RuntimeLine[4531:354370] age:6695, name: 萌萌, occupation: 教師, nationality:瑞典國
2016-04-10 01:25:38.837 RuntimeLine[4531:354370] {
age = 26;
associatedBust = "!Waning: key--value != nil !";
associatedCallBack = "!Waning: key--value != nil !";

name = "\U840c\U840c";
nationality = "\U745e\U5178\U56fd";
occupation = "\U6559\U5e08";

}
`
呵呵赋除, 又成功了,

  • 案例小結(jié):

看看我們都干了什么非凌?!What have we done荆针?3ㄎ恕!航背!
自己總結(jié)喉悴。。玖媚。

回顧一下:一共學了四個部分:1. Runtime的特征 2. Runtime的Category 3.Runtime的歸檔 功能 4. Runtime的數(shù)據(jù)轉(zhuǎn)換

下一篇繼續(xù): 《Runtime梳理(三)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末箕肃,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子今魔,更是在濱河造成了極大的恐慌勺像,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件错森,死亡現(xiàn)場離奇詭異吟宦,居然都是意外死亡,警方通過查閱死者的電腦和手機涩维,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門殃姓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事蜗侈∨衽疲” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵踏幻,是天一觀的道長枷颊。 經(jīng)常有香客問我,道長叫倍,這世上最難降的妖魔是什么偷卧? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮吆倦,結(jié)果婚禮上听诸,老公的妹妹穿的比我還像新娘。我一直安慰自己蚕泽,他們只是感情好晌梨,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著须妻,像睡著了一般仔蝌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荒吏,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天敛惊,我揣著相機與錄音,去河邊找鬼绰更。 笑死瞧挤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的儡湾。 我是一名探鬼主播特恬,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼徐钠!你這毒婦竟也來了癌刽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤尝丐,失蹤者是張志新(化名)和其女友劉穎显拜,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體摊崭,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡讼油,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了呢簸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片矮台。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡乏屯,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出瘦赫,到底是詐尸還是另有隱情辰晕,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布确虱,位于F島的核電站含友,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏校辩。R本人自食惡果不足惜窘问,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宜咒。 院中可真熱鬧惠赫,春花似錦、人聲如沸故黑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽场晶。三九已至混埠,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間诗轻,已是汗流浹背钳宪。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留扳炬,地道東北人使套。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像鞠柄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嫉柴,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

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