基本概念
- RPC(Remote Procedure Call)远程过程调用
- 本地过程调用:如果需要将本地student对象的age+1,可以实现一个addAge()方法,将student对象传入,对年龄进行更新之后返回即可,本地方法调用的函数体通过函数指针来指定。
- 远程过程调用:上述操作的过程中,如果addAge()这个方法由服务端下发
使用场景
根据后台推送过来的数据,进行动态页面跳转,跳转到页面后根据返回的数据执行对应的操作。
反射机制动态的创建类并执行方法
假设和后台约定格式如下:
- className类名
- propertys 数据参数
- method 调用方法名
@{
// 类名
@"className" : @"UserInfoViewController",
// 数据参数
@"propertys" : @{ @"name": @"liuxiaozhuang",
@"age": @3 },
// 调用方法名
@"method" : @"refreshUserInformation"
};
代码实现逻辑
// 简单封装的页面跳转方法,只是做演示,代码都是没问题的,使用时可以根据业务需求进行修改。
- (void)remoteNotificationDictionary:(NSDictionary *)dict {
// 根据字典字段反射出我们想要的类,并初始化控制器
Class class = NSClassFromString(dict[@"className"]);
UIViewController *vc = [[class alloc] init];
// 获取参数列表,使用枚举的方式,对控制器属性进行KVC赋值
NSDictionary *parameter = dict[@"propertys"];
[parameter enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// 在属性赋值时,做容错处理,防止因为后台数据导致的异常
if ([vc respondsToSelector:NSSelectorFromString(key)]) {
[vc setValue:obj forKey:key];
}
}];
[self.navigationController pushViewController:vc animated:YES];
// 从字典中获取方法名,并调用对应的方法
SEL selector = NSSelectorFromString(dict[@"method"]);
[vc performSelector:selector];
}
使用案例
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// 模拟远程调用,延迟十秒
[self testRemoteNotification];
return YES;
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[self remoteNotificationDictionary:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
// 简单封装的页面跳转方法,只是做演示,代码都是没问题的,使用时可以根据业务需求进行修改。
- (void)remoteNotificationDictionary:(NSDictionary *)dict {
// 根据字典字段反射出我们想要的类,并初始化控制器
Class class = NSClassFromString(dict[@"className"]);
UIViewController *vc = [[class alloc] init];
// 获取参数列表,使用枚举的方式,对控制器属性进行KVC赋值
NSDictionary *parameter = dict[@"propertys"];
[parameter enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
// 在属性赋值时,做容错处理,防止因为后台数据导致的异常
if ([vc respondsToSelector:NSSelectorFromString(key)]) {
[vc setValue:obj forKey:key];
}
}];
[self.naviController pushViewController:vc animated:YES];
// 从字典中获取方法名,并调用对应的方法
SEL selector = NSSelectorFromString(dict[@"method"]);
// 如果想消除黄色警告,可以通过clang编译指令消除
[vc performSelector:selector];
}
- (void)testRemoteNotification {
// 模拟远程通知的调用
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSDictionary *dict = @{
// 类名
@"className" : @"UserInfoViewController",
// 数据参数
@"propertys" : @{@"name": @"liuxiaozhuang",
@"age": @3},
// 调用方法名
@"method" : @"refreshUserInformation"};
[self application:[UIApplication sharedApplication] didReceiveRemoteNotification:dict fetchCompletionHandler:^(UIBackgroundFetchResult result) {
}];
});
}