iOS-runtime实践-消息推送跳转到任意页面并赋值

2017-04-17  本文已影响106人  c6e16b2e3a16

runtime的概念和作用不在这里多阐述,网上的文章很多.runtime的功能虽然很强大,但是在实际项目中写业务代码时很少用到.字典转Model已经有很好的轮子了,我们不用再自己去写(学习除外);非特殊情况,替换系统方法也几乎不会用到.本文介绍一种常见的runtime应用场景:消息推送.

应用收到消息推送时,会根据推动内容跳转到相应页面(控制器).推送消息的内容是以key:value的形式发送的,因此需要根据key:value来动态生成页面并跳转.

问题转换:根据字典来动态创建控制器并跳转.

1.约定推送消息(字典)格式

下图是友盟推送后台,消息推送时设置key:value键值对

image.png

因为要跳转到指定页面(控制器),则必须有一个键值对传递目标控制器的名称.其他的键值对可以是该页面所需要的属性值.

假设我的应用中有一个个人页面,需要根据推送内容显示推送的用户信息:

#import "PersonalViewController.h"

@interface PersonaViewController ()

@property (copy, nonatomic) NSString *name;
@property (assign, nonatomic) NSInteger age;
@property (copy, nonatomic) NSString *tel;

@end

@implementation PersonalViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    NSLog(@"%@, %ld, %@", _name, _age, _tel);
}

@end

那么推送消息内容可以这样设置:


E4791666-0082-4A37-ACB5-DFD2054BEE26.png

className是类名称
其他参数是该类所需要的属性值

2.APP接收通知并跳转

创建UINavigationController消息通知处理分类方便管理.

#import <UIKit/UIKit.h>

@interface UINavigationController (RemoteNotify)

- (void)pushWithUserInfo:(NSDictionary *)userInfo;

@end

#import "UINavigationController+RemoteNotify.h"
#import <objc/runtime.h>

@implementation UINavigationController (RemoteNotify)

- (void)pushWithUserInfo:(NSDictionary *)userInfo {
    if ([userInfo.allKeys containsObject:@"className"]) {
        NSString *className = [userInfo objectForKey:@"className"];
        Class class = NSClassFromString(className);
        id instance = [[class alloc] init];
        if (instance) {
            [userInfo enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
                if (![key isEqualToString:@"className"]) {
                    if ([self containsProperty:instance key:key]) {
                        [instance setValue:obj forKey:key];
                    } else {
                        NSLog(@"不包含(%@:%@)", key, obj);
                    }
                }
            }];
            [self pushViewController:instance animated:YES];
        }
    }
}

- (BOOL)containsProperty:(id)instance key:(NSString *)key {
    unsigned int count;
    objc_property_t *properties = class_copyPropertyList([instance class], &count);
    for (int i = 0; i < count; i++) {
        objc_property_t property = properties[i];
        NSString *name = [NSString stringWithCString: property_getName(property) encoding:NSUTF8StringEncoding];
        if ([key isEqualToString:name]) {
            return YES;
        }
    }
    free(properties);
    return NO;
}

@end

在AppDelegate的消息接收方法中调用

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    //获取当前控制器
    UITabBarController *rootCtrl = (UITabBarController *)self.window.rootViewController;
    UINavigationController *currentCtrl = (UINavigationController *)rootCtrl.selectedViewController; 
    //从当前控制器push到指定控制器
    [currentCtrl pushWithUserInfo:userInfo];
}
上一篇下一篇

猜你喜欢

热点阅读