這一章分成四個部分進行學習: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"];
- 下面獲得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
? 不意外嗎?飒硅!
- 獲得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
也獲取了梯轻,還不意外?尽棕!
還順便理解了property
和Ivar
區(qū)別吧
- 獲取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梳理(三)》