Runtime之界面跳转

有时候面对推送会有很多的的类型,要跳到不同界面,看了cocoaChina之后使用runtime进行这样的逻辑操作会好很多。

首先说一下适用的环境:

  • 推送:根据服务端推送过来的数据规则,跳转到对应的控制器

  • feeds列表:不同类似的cell,可能跳转不同的控制器

具体就是先跟服务器那边说好推送规则,里面有要跳的类的类名,和相关的属性及其值,然后在接到推送的时候使用runtime的动态创建对象进行跳转,由于使用了runtime之后对类来说属性就不分基本数据类型或者非基本数据类,可以不进行解包和封包操作。

具体代码如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
- (void)push:(NSDictionary *)params
{
// 类名
NSString *class =[NSString stringWithFormat:@"%@", params[@"class"]];
const char *className = [class cStringUsingEncoding:NSASCIIStringEncoding];
// 从一个字串返回一个类
Class newClass = objc_getClass(className);
if (!newClass)// 没有这个类
{
// 创建一个类
Class superClass = [NSObject class];
newClass = objc_allocateClassPair(superClass, className, 0);
// 注册你创建的这个类
// 使用objc_allocate..方法创建类的时候必须使用这个方法注册,然后才能够使用这个类
objc_registerClassPair(newClass);
}

// 创建对象
id instance = [[newClass alloc] init];

// 对该对象赋值属性
NSDictionary * propertys = params[@"property"];
[propertys enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 检测这个对象是否存在该属性
if ([self checkIsExistPropertyWithInstance:instance verifyPropertyName:key]) {
// 利用kvc赋值
[instance setValue:obj forKey:key];
}
}];

// 获取导航控制器
UIWindow * keyWindow = [UIApplication sharedApplication].keyWindow;
UINavigationController * pushClassStance = (UINavigationController *)keyWindow.rootViewController;

// 跳转到对应的控制器
[pushClassStance pushViewController:instance animated:YES];
}
/**
* 检查一个对象中是否存在某一个属性
*
* @param instance 某一个对象
* @param verifyPropertyName 某一个属性
*
*/
- (BOOL)checkIsExistPropertyWithInstance:(id)instance verifyPropertyName:(NSString *)verifyPropertyName
{
unsigned int outCount, i;
// 获取对象里的属性列表
objc_property_t * properties = class_copyPropertyList([instance class], &outCount);// 这里用了copy,会进行内存引用计数加1
for (i = 0; i < outCount; i++) {
objc_property_t property =properties[i];
// 属性名转成字符串
NSString *propertyName = [[NSString alloc] initWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
// 判断该属性是否存在
if ([propertyName isEqualToString:verifyPropertyName]) {
free(properties);// 所以要记得释放
return YES;
}
}
free(properties);// 还有这里,所以要记得释放
return NO;
}

那么举个例子,这里的推送规则是这样的:

1
2
3
4
NSDictionary *userInfo = @{@"class": @"HLLTableViewController",
@"property": @{@"titleName": @"HLL"}};

[self push:userInfo];

其实这样的做法还有一个弊端,和KVC一样,服务器推送过来的类名要够正确没有错别字。