这一章分成四个部分进行学习:1. Runtime的特征 2. Runtime的Category 3.Runtime的归档 功能 4. Runtime的数据转换
第一部分: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); // 去内存
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文件中
变量什么 私有变量? 匿名扩展相关知识自己补充了,这里不赘述了
我们来验证一下我们获得了什么吧?
> ````
// 首先 添加对象
Gril * grilTeacher = [[Gril alloc] init];
grilTeacher.name = @"女教师";
grilTeacher.age = 26;
[grilTeacher setValue:@"教师" forKey:@"occupation"];
- 下面获得property
NSDictionary * dict = [grilTeacher allProperties];
NSLog(@"%@", dict);
打印结果:
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);
打印结果:
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
区别吧
- 获取Methods
NSDictionary * dict = [grilTeacher allmethods];
NSLog(@"%@", dict);
打印结果:
2016-04-09 20:09:39.363 RuntimeLine[2372:204392] { ".cxx_destruct" = 0;// 这个方法这在ARC的环境下才会被调用 销毁意思 age = 0; allProperties = 0; //++ allmethods = 0; //++ allvars = 0; --- heigth = 0; name = 0; "setAge:" = 1; ???? "setHeigth:" = 1; ??? "setName:" = 1; ??? }
很牛逼吧,set get
方法 内存管理机制 ???还不很意外了吗???!
不能做的都做了, 万能吧,还真是,
这就是Runtime?Objective-C objc
的根基所在
第二部分:Runtime的Category
- 创建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
{
// 关联对象 objc_association_retain_nonatomc
objc_setAssociatedObject(self, @selector(associatedBust), bust, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSNumber *)associatedBust
{
// 获取关联
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);
输出结果呢?
`
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. 为了将应用数据存储到硬盘中,iOS提供基本的文件`API`、`Property List`序列化、`SQLite`、`CoreData`以及`NSCoding`。
2. 是类对象本身数据的写入到本地文件。
我 们需要实现两个方法: `encodeWithCoder`和`initWithEncoder`。`encodeWithCoder`就是编码,`initWithCoder`就是解码。 `encodeWithCoder`方法传入的是一个`NSCoder`对象,实现的时候我们就可以调用`encodeObject、encodeFloat、 encodeInt`等各种方法并通过指定键值进行编码。
* 下面我们写专业一点 归档嘛
> ````
// Gril.h
#import <Foundation/Foundation.h>
@interface Gril : NSObject <NSCoding>
@property (copy, nonatomic) NSString * occupation; // 专业
@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的数据转换
> 反之,当服务器返回了大量数据,iOS端这边接收后如何去转换呢?在我们的项目中也用到过这些`json`转成Model三方库:MJExtention、YY。。。忘了,下面了解下runtime实现JSON和Model互转。
* 还是用我们类Gril吧, 我就喜欢用Gril来表达一下
> ````
// Gril.h
#import <Foundation/Foundation.h>
@interface Gril : NSObject
@property (copy, nonatomic) NSString * occupation; // 专业
@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" : @"瑞典国"
};
// 字典转模型
Gril * grilTeacher = [[Gril alloc] initWithDictionary:dict];
NSLog(@"age:%d, name: %@, occupation: %@, nationality:%@", (int)grilTeacher.age, grilTeacher.name, grilTeacher.occupation, grilTeacher.nationality);
// 模型转字典
NSDictionary * modelDict = [grilTeacher covertToDictionary];
NSLog(@"%@",modelDict);
我们来看一下打印的结果是否成功吧:
`
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";
}
`
呵呵, 又成功了,
案例小结:
看看我们都干了什么?!What have we done?!!!
自己总结。。。
回顾一下:一共学了四个部分:1. Runtime的特征 2. Runtime的Category 3.Runtime的归档 功能 4. Runtime的数据转换
下一篇继续: 《Runtime梳理(三)》