首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >iOS初步集成极光推送后你还要做这些事

iOS初步集成极光推送后你还要做这些事

作者头像
Raindew
发布于 2018-06-14 06:33:13
发布于 2018-06-14 06:33:13
3.1K00
代码可运行
举报
运行总次数:0
代码可运行
当我们把推送证书配置好再把极光SDK拖入项目配置,然后注册极光推送,完成代理,这样没有太多意外你就能收到消息了,但是我们都知道还需要做一些处理,都是哪些呢?

当收到消息时,app在前台如何处理

在后台如何处理?
未启动如何处理?
当app在前台收到消息如何跳转到指定页面?
在后台收到系统通知,点击通知栏又如何跳转指定页面?
未启动时点击通知栏又如何跳转指定页面?
收到自定义通知如何显示?
怎么给指定用户发送消息?
当有多个类型通知的时候,怎么拿到服务器发送过来的extras的内容,然后根据类型做出正确的跳转?
怎么在app内部开启、关闭通知?
你测试包(真机调试)收到通知后,怎么确定上架包也能收到消息?

今天小伙伴问我Badge怎么弄,我这边徽章个数是从服务器请求的,使用WZLBadge这个三方绘制的。另外,我个人遇到的一个崩溃问题 觉得有必要让大家看下。

在上面我抛出了一些问题,基本都是我们集成极光后前端需要处理的事情,下面我一个个解决这些问题。我个人没有总结太多,肯定有缺失,这里只是给不知道的伙伴列举一些常见的。若有误,请指出。

当收到消息时,app在前台如何处理?如何跳转?

当应用在前台时,接收到通知消息首先会调用极光的这个代理

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma mark- JPUSHRegisterDelegate
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
 // Required
    NSDictionary * userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]
        ]) {
        [JPUSHService handleRemoteNotification:userInfo];
        
    }
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置
       completionHandler(UNNotificationPresentationOptionSound); 
    }else if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {//后台
        // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置
        completionHandler(UNNotificationPresentationOptionAlert); 
    }else {//未启动
        // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置
        completionHandler(UNNotificationPresentationOptionAlert); 
    }
}

在上面代理中有几个判断,当app在前台、后台、未运行。三种状态,解释下

Badge:应用角标 Sound:通知声音 Alert:通知栏 如果你同时需要通知栏展示,声音,角标,只需要以|符号连接即可,不需要的直接删除。

如果你在应用内收到通知(非自定义消息,后面会详细说这个),应该在这个 if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {}判断中进行提示、跳转。你可以在这里写一个UIAlertController提示,也可以像我一样提示在顶部,取决你们UI设计。

我的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        
        /*
         *      当应用在前台  接到通知
         */
        NSString *messageAlert = [[userInfo objectForKey:@"aps"]objectForKey:@"alert"];

        //获取顶层控制器
        UIViewController *currentVC = [self currentViewController];
    
        [TSMessage showNotificationInViewController:currentVC.navigationController
                                              title:@"系统通知"
                                           subtitle:messageAlert
                                              image:[UIImage imageNamed:@"notifi"]
                                               type:TSMessageNotificationTypeMessage
                                           duration:TSMessageNotificationDurationAutomatic
                                           callback:^{
                                               if (currentVC.navigationController) {
                                                   if ([Person currentLoginUser].userId.length == 11) {
                                                       //先跳转指定tab然后push到指定页面
                                                       BaseTabBarController *myTbabar = (BaseTabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                                                       myTbabar.selectedIndex = 2;
                                                       //改变bar后再次获取当前控制器
                                                       UIViewController *VC = [self currentViewController];
                                                       MyServiceViewController *vc = [[MyServiceViewController alloc] init];
                                                       [vc setHidesBottomBarWhenPushed:YES];
                                                       [VC.navigationController pushViewController:vc animated:YES];
                                                   }else {
                                                       [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
                                                   }
                                               }else {
                                                   [SVProgressHUD showErrorWithStatus:@"跳转失败,请自行前往个人中心查看。"];
                                               }

                                           }
                                        buttonTitle:nil
                                     buttonCallback:^{
                                     }
                                         atPosition:TSMessageNotificationPositionNavBarOverlay
                               canBeDismissedByUser:YES];
        completionHandler(UNNotificationPresentationOptionSound); // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置

    }

上面代码我选择了一个提示的第三方TSMessage在点击消息的时候做了一个跳转。在调用这个三方的时候你首先要获取当前顶层控制器赋值给这个三方。 UIViewController *currentVC = [self currentViewController];

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//获取Window当前显示的ViewController
- (UIViewController*)currentViewController{
    //获得当前活动窗口的根视图
    UIViewController* vc = [UIApplication sharedApplication].keyWindow.rootViewController;
    while (1) {
        //根据不同的页面切换方式,逐步取得最上层的viewController
        if ([vc isKindOfClass:[UITabBarController class]]) {
            vc = ((UITabBarController*)vc).selectedViewController;
        }
        if ([vc isKindOfClass:[UINavigationController class]]) {
            vc = ((UINavigationController*)vc).visibleViewController;
        }
        if (vc.presentedViewController) {
            vc = vc.presentedViewController;
        }else{
            break;
        }
    }
    return vc;
}

有个细节是,当你跳转指定控制器的时候,你有必要判断当前控制器是否可以push过去,即有没有导航栏,如果没有则不能push,当然也可以像我这样先跳转到个人中心,保证有导航栏,但是这样的处理也许不适用你的app.

在后台收到消息如何处理?如何跳转?

当你在后台,收到消息,通知栏会弹出一个系统alert,一旦你点击了这个alert,目标app会被唤起,同时调用下面代理函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler;

在这个函数中我们做这样的提示、跳转处理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 // Required
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
                
        /*
         *     应用在后台  点击了通知栏
         */
        UIViewController *currentVC = [self currentViewController];
        if (currentVC.navigationController) {
            if ([Person currentLoginUser].userId.length == 11) {
                //先跳转指定tab然后push到指定页面
                BaseTabBarController *myTbabar = (BaseTabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                myTbabar.selectedIndex = 2;
                MyServiceViewController *vc = [[MyServiceViewController alloc] init];
                [vc setHidesBottomBarWhenPushed:YES];
                //改变bar后再次获取当前控制器
                UIViewController *VC = [self currentViewController];
                [VC.navigationController pushViewController:vc animated:YES];
            }else {
                [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
            }
        }else {
            //避免没有导航栏跳转崩溃的问题
            [SVProgressHUD showErrorWithStatus:@"跳转失败,请自行前往个人中心查看。"];
        }
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler(); // 系统要求执 这个 法

以上跳转代码、获取当前顶层控制器都是相同的,不再解释。

未启动时受到消息如何处理?如何跳转

这种情况是最不容易找到的,因为当你的应用未启动,点击了通知栏,它没有调用任何极光的代理,这时候需要我们去启动函数进行判断。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [self appStateInactive:launchOptions];
}

在上面启动函数中调用一个方法,来判断是否是收到通知启动的。最后,进行目标控制器跳转。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (void)appStateInactive:(NSDictionary *)launchOptions {
      /*
 *     当应用不在后台    点击通知栏
 */
NSDictionary* pushInfo = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
if (pushInfo) {
    NSDictionary *apsInfo = [pushInfo objectForKey:@"aps"];
    if(apsInfo) {
        [self.mainTab.tabBar showBadgeOnItemIndex:2];
        UIViewController *currentVC = [self currentViewController];
        if (currentVC.navigationController) {
            if ([Person currentLoginUser].userId.length == 11) {
                //先跳转指定tab然后push到指定页面
                BaseTabBarController *myTbabar = (BaseTabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                myTbabar.selectedIndex = 2;
                MyServiceViewController *vc = [[MyServiceViewController alloc] init];
                [vc setHidesBottomBarWhenPushed:YES];
                //更改后bar后再次获取当前控制器
                UIViewController *VC = [self currentViewController];
                [VC.navigationController pushViewController:vc animated:YES];
            }else {
                [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
            }
        }
    }
    
}
                
}

收到自定义通知如何显示?

自定义消息,这个比较特殊,它必须是在app正在前台的时候才能收到消息,收到消息的位置而且不在代理中,而是在一个通知中。

当注册极光后可以加入下面代码。注册一个通知。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 注册通知   当收到自定义消息的时候
    [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(networkDidReceiveMessage:)
                                                     name:kJPFNetworkDidReceiveMessageNotification
                                                   object:nil];

这个通知类型极光文档是这样解释的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
kJPFNetworkDidReceiveMessageNotification // 收到消息(非APNS)

实现这个通知方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/*
 *      当在前台  接收到  自定义消息 通知
 */
- (void)networkDidReceiveMessage:(NSNotification *)notification {
    
    //有没有未读消息
    [self.mainTab.tabBar showBadgeOnItemIndex:2];
    
    
    NSDictionary *userInfo = [notification userInfo];
    NSString *content = [userInfo valueForKey:@"content"];
      
    //获取顶层
    UIViewController *currentVC = [self currentViewController];
    [TSMessage showNotificationInViewController:currentVC.navigationController
                                          title:@"系统通知"
                                       subtitle:content
                                          image:[UIImage imageNamed:@"notifi"]
                                           type:TSMessageNotificationTypeMessage
                                       duration:TSMessageNotificationDurationAutomatic
                                       callback:^{
                                           //判断是否有导航栏
                                           if (currentVC.navigationController) {
                                               if ([Person currentLoginUser].userId.length == 11) {
                                                   //先跳转指定tab然后push到指定页面
                                                   BaseTabBarController *myTbabar = (BaseTabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                                                   myTbabar.selectedIndex = 2;
                                                   //改变bar后再次获取当前控制器
                                                   UIViewController *VC = [self currentViewController];
                                                   MyServiceViewController *vc = [[MyServiceViewController alloc] init];
                                                   [vc setHidesBottomBarWhenPushed:YES];
                                                   [VC.navigationController pushViewController:vc animated:YES];
                                               }else {
                                                   [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
                                               }
                                           }else {//没有导航栏
                                               [SVProgressHUD showErrorWithStatus:@"跳转失败,请自行前往个人中心查看。"];
                                           }
                                       }
                                    buttonTitle:nil
                                 buttonCallback:^{
                                 }
                                     atPosition:TSMessageNotificationPositionNavBarOverlay
                           canBeDismissedByUser:YES];

}

上面代码几乎和在前台收通知的代码是一样的。有点需要说明的是这里我直接取的content这个key。我这边让后台传的是这个,当然也有后台会放extras这个字段的json数据,我后面会有代码详细说这个解析。

怎么给指定用户发送消息?

通知一般不是广播式的,有时候需要针对不同用户群体或者个体发送通知,例如优惠券等。极光提供了几种区分用户的方法,在Web中我们可以看到

image.png

设备标签、别名、ID、群推

标签和别名差不多。只说别名。现在有这个场景:我想给我所有的注册用户推送消息,没注册的不想推。

这时候,你需要在极光登录成功(非常重要,否则你可能出现注册别名无效的情况)的通知方法中向极光服务器注册Alias。如下代码,建议以userId或者服务器登录返回tag值注册,这样后台方便发送消息。登录成功的通知名称:kJPFNetworkDidLoginNotification

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[JPUSHService setAlias:userId callbackSelector:@selector(alias:) object:self];

这样你在web选择对应别名发送通知,就可以推送到希望推送到的手机上了。

当有多个类型通知的时候,怎么拿到服务器发送过来的extras的内容,然后根据类型做出正确的跳转?

在上面我们一直说的都是在控制台直接发送消息,然而实际上我们推送都是后台开发人员以API的形式对接极光的服务器。通知往往携带一些所需的参数,例如红包里面的金额cost...不多说废话,直接看我的解析代码吧!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
//json解析
- (NSDictionary *)jsonWithString:(NSString *)dataString {
    NSData *data = [dataString dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
    return dic;
}
//内部收到消息,提示
- (void)showMessageWithUserInfo:(NSDictionary *)userInfo {
    
    //获取顶层控制器
    [self.mainTab.tabBar showBadgeOnItemIndex:2];
    UIViewController *currentVC = [self currentViewController];
    NSString *messageAlert = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"];
    NSString *extras = [userInfo objectForKey:@"extras"];
    NSDictionary *dic = [self jsonWithString:extras];
    
    NSString *notifiType = [NSString stringWithFormat:@"%@",dic[@"messag_type"]];
    
    [TSMessage showNotificationInViewController:currentVC.navigationController title:@"系统通知" subtitle:messageAlert image:[UIImage imageNamed:@"notifi"] type:TSMessageNotificationTypeMessage duration:TSMessageNotificationDurationAutomatic callback:^{
        if (currentVC.navigationController) {
            if ([Person currentLoginUser].userId.length == 11) {
                if ([notifiType isEqualToString:@"1"]) {//消息类型
                    CommentViewController *vc = [[CommentViewController alloc] initWithNibName:@"CommentViewController" bundle:nil];
                    vc.orderTitle = dic[@"item_title"];
                    vc.remark = dic[@"comments"];
                    vc.time = dic[@"item_time"];
                    vc.orderId = [NSString stringWithFormat:@"%@",dic[@"item_id"]];
                    [vc setHidesBottomBarWhenPushed:YES];
                    [currentVC.navigationController pushViewController:vc animated:YES];
                }else {
                    //其他消息类型
                }
                
            }else {
                [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
            }
        }else {
            [SVProgressHUD showErrorWithStatus:@"跳转失败,请自行前往个人中心查看。"];
        }
    } buttonTitle:nil buttonCallback:^{
    } atPosition:TSMessageNotificationPositionNavBarOverlay
                           canBeDismissedByUser:YES];
    
}
//外部收到消息。点击了消息
- (void)touchAlertWithUserInfo:(NSDictionary *)userInfo {
    
    [self.mainTab.tabBar showBadgeOnItemIndex:2];
    UIViewController *currentVC = [self currentViewController];
    NSString *extras = userInfo[@"extras"];
    NSDictionary *dic = [self jsonWithString:extras];
    NSString *notifiType = [NSString stringWithFormat:@"%@",dic[@"messag_type"]];
    
    if (currentVC.navigationController) {
        if ([Person currentLoginUser].userId.length == 11) {
            if ([notifiType isEqualToString:@"1"]) {//消息类型
                //先跳转指定tab然后push到指定页面
                BaseTabBarController *myTbabar = (BaseTabBarController *)[UIApplication sharedApplication].keyWindow.rootViewController;
                myTbabar.selectedIndex = 1;
                //改变bar后再次获取当前控制器
                UIViewController *VC = [self currentViewController];
                CommentViewController *vc = [[CommentViewController alloc] initWithNibName:@"CommentViewController" bundle:nil];
                vc.orderTitle = dic[@"item_title"];
                vc.remark = dic[@"comments"];
                vc.time = dic[@"item_time"];
                vc.orderId = [NSString stringWithFormat:@"%@",dic[@"item_id"]];
                [vc setHidesBottomBarWhenPushed:YES];
                [VC.navigationController pushViewController:vc animated:YES];
            }
            
        }else {
            [SVProgressHUD showInfoWithStatus:@"请登录后,前往我的服务查看。"];
        }
    }else {
        [SVProgressHUD showErrorWithStatus:@"跳转失败,请自行前往个人中心查看。"];
    }
}

我把以上方法独立出来。方法都有注释,不再讲解。那么,这时候我仅仅需要在合适的位置调用这些方法即可!

例如。在后台的时候

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    // Required
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    if([response.notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        /*
         *     应用在后台  点击了通知栏
         */
        [self touchAlertWithUserInfo:userInfo];
        [JPUSHService handleRemoteNotification:userInfo];
    }
    completionHandler(); // 系统要求执 这个 法
}

在前台的时候

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// iOS 10 Support
- (void)jpushNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(NSInteger))completionHandler {
    // Required
    NSDictionary *userInfo = notification.request.content.userInfo;
    if([notification.request.trigger isKindOfClass:[UNPushNotificationTrigger class]
        ]) {
        [JPUSHService handleRemoteNotification:userInfo];
    }
    if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
        
        /*
         *      当应用在前台  接到通知
         */
        NSLog(@"userInfo : %@",userInfo);
        //提示
        [self showMessageWithUserInfo:userInfo];
        completionHandler(UNNotificationPresentationOptionSound); // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置

    }else if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {//后台
        completionHandler(UNNotificationPresentationOptionAlert); // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置
    }else {//未启动
        completionHandler(UNNotificationPresentationOptionAlert); // 需要执 这个 法,选择 是否提醒 户,有Badge、Sound、Alert三种类型可以选择设置
    }
}

我们看到通过方法独立出来,我们的代码更简洁,逻辑也更清晰了。

怎么在app内部开启、关闭通知?

一般都在app设置中有一个switch的开关。来开启关闭通知,代码很简单,直接贴上来。有一点需要注意,就是这个开关的状态需要存到本地,有高要求的存服务器。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
cell.textLabel.text = @"消息提醒";
        UISwitch *swi = [[UISwitch alloc] initWithFrame:CGRectMake(CGRectGetWidth(cell.frame)-15,7.5, 45, 30)];
        //存储到本地
        NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
        NSString *isNotification = [defaults objectForKey:@"isNotification"];
        NSLog(@"noti %@",isNotification);
        if ([isNotification isEqualToString:@"0"]) {
            swi.on = NO;
        }else {
            swi.on = YES;
        }
        [swi addTarget:self action:@selector(onOrOff:) forControlEvents:UIControlEventValueChanged];
        [cell.contentView addSubview:swi];
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#pragma mark -- 消息推送的 开/- (void)onOrOff:(UISwitch *)swi {
    NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
    if (!swi.on) {//存入本地
        [[UIApplication sharedApplication] unregisterForRemoteNotifications];//关闭
        [defaults setObject:@"0" forKey:@"isNotification"];
    }else {
        [[UIApplication sharedApplication] registerForRemoteNotifications];
        [defaults setObject:@"1" forKey:@"isNotification"];
    }
}
另外,不要忘记!你需要在启动代理中也进行判断开关
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
   //是否关闭了推送?
    NSUserDefaults *defaults = [[NSUserDefaults alloc] init];
    NSString *isNotification = [defaults objectForKey:@"isNotification"];
    if ([isNotification isEqualToString:@"0"]) {
        [[UIApplication sharedApplication] unregisterForRemoteNotifications];//关闭
    }else {
        [[UIApplication sharedApplication] registerForRemoteNotifications];//开启
    }
}

你测试包(真机调试)收到通知后,怎么确定上架包也能收到消息?

想要测试上架包,首先更改极光注册代码。production改为YES

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
[JPUSHService setupWithOption:launchOptions appKey:kJPushAPPKey channel:@"apsForProduction" apsForProduction:YES
            advertisingIdentifier:nil];

(开发、生产证书配置不再说,网上很多)这个就涉及到打包的知识了,开发环境就是真机调试的我就不说了。我们这里使用蒲公英平台安装生产环境包,archive后选择

image.png

然后选择Ad Hoc

image.png

这样打包就是生产包了。如果你没有对应的证书可以去配置,同时你还需要配置对应描述文件。

iOS技术交流群:511860085 成堆的技术视频福利,欢迎加入!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.03.28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
二叉树遍历的应用:判断二叉树的类别
昨天的文章讲述了二叉树的先序、中序和后序的遍历方法(递归和非递归),但是这种遍历方法有什么意义么?今天来讲讲这些算法可以用来做什么,只要稍加更改,我们就可以得到另外一个功能,只需要仅仅几行代码的修改! 还记得上篇文章二叉树的分类么?今天我们要来说三种树的分类:完全二叉树、平衡二叉树和搜索二叉树!
算法工程师之路
2019/08/05
5450
树形DP
 假设现在有一棵树,我只要求出每个结点作为头节点对应子树的最大值和最小值,那么最终答案一定在其中,因此每个结点都有两个信息,最大值和最小值,我把这个信息封装为一个结构体,带入递归中,就能求出最终答案,最大值就等于当前结点左子树的最大值和右子树的最大值和当前结点的值三者中最大的那一个,最小值也是三者中最小的那一个。
mathor
2018/08/16
1.6K0
树形DP
LeetCode110.平衡二叉树
 平衡二叉树的定义是一个二叉树每个结点的左右两个子树的高度差绝对值不超过1(可以是1),用一个结构体来保存某个结点的信息(包括是否是平衡树,高度多少),算法流程如下:
mathor
2018/08/17
4940
LeetCode110.平衡二叉树
【算法】论平衡二叉树(AVL)的正确种植方法
参考资料 《算法(java)》                           — — Robert Sedgewick, Kevin Wayne 《数据结构》                                  — — 严蔚敏 2017年度原创IT博客评选:http://www.itbang.me/goVote/203 引子 近日, 为了响应市政府“全市绿化”的号召, 身为共青团员的我决定在家里的后院挖坑种二叉树,以支援政府实现节能减排的伟大目标,并进一步为实现共同富裕和民族复兴打下坚实
啦啦啦321
2018/03/30
1.1K0
【算法】论平衡二叉树(AVL)的正确种植方法
什么是平衡二叉树
上篇文章里面,我们已经学习了二叉搜索树的相关内容,二叉搜索树有一个缺点,在插入数据是有序的序列(包括升序和降序),会导致二叉树退化成链表,从而导致在查找,删除,添加时的性能均从O(logN)降低为O(N),这是不能接受的。如下图:
我是攻城师
2019/04/28
7.4K0
什么是平衡二叉树
【算法】搜索二叉树,完全二叉树,平衡二叉树的判断
它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
MapleYe
2020/03/28
1.1K0
AVL树(平衡二叉树)
为什么叫AVL树?   因为AVL树是由 G.M.Adelson-Velsky 和 E.M.Landis 这两位俄罗斯科学家在1962年的论文中首次提出,是最早的自平衡二分搜索树结构。   由于AVL树是自平衡二分搜索树,所以本质上还是二分搜素树,也就是二分搜索树的性质AVL树都满足,由于二分搜索树在添加有序元素时,会退化成链表,造成时间复杂度为O(n),但AVL树是不会出现这种情况的,因为AVL树通过自平衡来解决了退化成链表的问题,关于二分搜索树,你可以看我之前二分搜索树(Binary Search Tree)这篇文章。 平衡二叉树:对于任意一个节点,左子树和右子树的高度差都不能超过1。
程序员波特
2024/01/19
1920
AVL树(平衡二叉树)
自已动手作图搞清楚AVL树
二叉树是一种常用的数据结构,更是实现众多算法的一把利器。 二分搜索树(Binary Search Tree)做为一种能实现快速定位查找的二叉树也得到了广泛应用
智慧zhuhuix
2020/08/14
6470
自已动手作图搞清楚AVL树
【算法】二叉查找树(BST)实现字典API
该文介绍了在技术社区中如何从技术角度、业务角度、架构角度、工程角度、团队协作角度、社区运营角度、软件工程角度、编程语言角度去分析思考问题,通过实例介绍了这些方法的应用,并总结了一些思考框架。
啦啦啦321
2018/01/03
1.7K0
【算法】二叉查找树(BST)实现字典API
二叉树刷题总结:二叉树的属性
这就需要去判断根节点下左子树与右子树里侧和外侧是否相等。比较的方法是拿左子树的 “左-右-中” 节点和右子树的“右-左-中”为顺序的节点做比较。
HelloWorld杰少
2022/08/04
3760
二叉树刷题总结:二叉树的属性
【算法总结】五道常见的算法-二叉树
前段时间,写了面试必备的一系列文章,反应还不错。有一些读者反馈说,能不能整理一些面试常见的算法。前段时间,我恰好总结了 LeetCode 常见的面试算法题目。
程序员徐公
2022/01/20
1.1K0
【算法总结】五道常见的算法-二叉树
数据结构之AVL树
我们先来回忆一下二分搜索树所存在的一个问题:当我们按顺序往二分搜索树添加元素时,那么二分搜索树可能就会退化成链表。例如,现在有这样一颗二分搜索树:
端碗吹水
2021/02/02
5250
【数据结构】二叉树全攻略,从实现到应用详解
树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。
2的n次方
2024/10/15
1980
【数据结构】二叉树全攻略,从实现到应用详解
LeetCode 二叉树系统题解
TIPS:前中后序遍历区别在于三字中的中间那个字,前、中、后序分别对应左、根、右。
Yano_nankai
2019/11/10
9940
LeetCode 二叉树系统题解
二叉树的最大深度
使用前序(中左右),也可以使用后序遍历(左右中),使用前序求的就是深度,使用后序求的是高度。
用户11097514
2024/05/30
860
美团面试官:你对二叉树后续遍历一无所知
其实二叉树的题目真的不难,无非就是前中后序遍历框架来回倒嘛,但是对于有的题目,不同的遍历顺序时间复杂度不同。
labuladong
2021/09/23
5560
二叉树的操作及常见面试题
本文将附上博主自己手动实现的二叉树常见的各种操作以及归纳总结一下常见的基础面试题。
VIBE
2022/12/02
3890
二叉树——104. 二叉树的最大深度
方法一:深度优先搜索 如果我们知道了左子树和右子树的最大深度Ⅰ和r,那么该二叉树的最大深度即为 max(l, r)+1 而左子树和右子树的最大深度又可以以同样的方式进行计算。因此我们可以用「深度优先搜索」的方法来计算二叉树的最大深度。具体而言,在计算当前二叉树的最大深度时,可以先递归计算出其左子树和右子树的最大深度,然后在O(1)时间内计算出当前二叉树的最大深度。递归在访问到空节点时退出。 复杂度分析 时间复杂度:O(n),其中n为二叉树节点的个数。每个节点在递归中只被遍历一次。 空间复杂度:O(height),其中height表示二叉树的高度。递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度。 方法二:广度优先搜索 我们也可以用「广度优先搜索」的方法来解决这道题目,但我们需要对其进行—些修改,此时我们广度优先搜索的队列里存放的是「当前层的所有节点」。每次拓展下一层的时候,不同于广度优先搜索的每次只从队列里拿出一个节点,我们需要将队列里的所有节点都拿出来进行拓展,这样能保证每次拓展完的时候队列里存放的是当前层的所有节点,即我们是一层一层地进行拓展,最后我们用一个变量ans来维护拓展的次数,该二叉树的最大深度即为ans。 复杂度分析 ·时间复杂度:O(n),其中n为二叉树的节点个数。与方法一同样的分析,每个节点只会被访问一次。 ·空间复杂度:此方法空间的消耗取决于队列存储的元素数量,其在最坏情况下会达到O(n)。
向着百万年薪努力的小赵
2022/12/02
2940
二叉树——104. 二叉树的最大深度
计算二叉树的最大高度
参考链接:Iterative Method to find Height of Binary Tree
九州暮云
2019/08/21
5K0
为实习准备的数据结构(4)-- 二叉树
==特别标注:如果二叉树中有相同值元素的存在,那么有极大概率还原失败,下面中、后序遍历也是==
看、未来
2021/03/17
4170
相关推荐
二叉树遍历的应用:判断二叉树的类别
更多 >
LV.3
这个人很懒,什么都没有留下~
目录
  • 当我们把推送证书配置好再把极光SDK拖入项目配置,然后注册极光推送,完成代理,这样没有太多意外你就能收到消息了,但是我们都知道还需要做一些处理,都是哪些呢?
  • ● 在后台如何处理?
  • ● 未启动如何处理?
  • ● 当app在前台收到消息如何跳转到指定页面?
  • ● 在后台收到系统通知,点击通知栏又如何跳转指定页面?
  • ● 未启动时点击通知栏又如何跳转指定页面?
  • ● 收到自定义通知如何显示?
  • ● 怎么给指定用户发送消息?
  • ● 当有多个类型通知的时候,怎么拿到服务器发送过来的extras的内容,然后根据类型做出正确的跳转?
  • ● 怎么在app内部开启、关闭通知?
  • ● 你测试包(真机调试)收到通知后,怎么确定上架包也能收到消息?
  • 在上面我抛出了一些问题,基本都是我们集成极光后前端需要处理的事情,下面我一个个解决这些问题。我个人没有总结太多,肯定有缺失,这里只是给不知道的伙伴列举一些常见的。若有误,请指出。
  • 设备标签、别名、ID、群推
  • 另外,不要忘记!你需要在启动代理中也进行判断开关
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档