NSNotification相关常见问题
实现原理(结构设计、通知如何存储的、name&observer&SEL之间的关系等)
通知的发送时同步的,还是异步的
NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息NSNotificationQueue是异步还是同步发送?在哪个线程响应
NSNotificationQueue和runloop的关系
如何保证通知接收的线程在主线程
页面销毁时不移除通知会崩溃吗
多次添加同一个通知会是什么结果?多次移除通知呢
一.NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息
默认情况下,发送通知和接收通知的处理在同一个线程
NSNotificationCenter 的 post 方法(如 post(name:object:userInfo:))是同步执行的:
• 当在线程 A 中调用 post 发送通知时,通知中心会立即遍历所有观察者,在当前线程 A 中同步调用观察者的处理方法(即观察者注册时指定的 selector 或闭包)。
• 因此,发送通知的线程与接收通知的处理线程是同一个线程,直到所有观察者处理完毕,post 方法才会返回。
2. 如何“异步发送通知”?
若希望通知的发送或处理过程异步执行(避免阻塞当前线程,或让处理逻辑在其他线程执行),有两种常见方式:
方式一:使用 NotificationQueue 实现异步发送
NotificationQueue 是与通知中心配合使用的“通知队列”,可以实现通知的延迟/异步发送。它通过 enqueue 方法将通知入队,而非直接发送,支持三种发送策略:
• NSPostNow:立即发送(同步,等价于直接调用 post)。
• NSPostASAP:尽快发送(在当前 RunLoop 周期结束前异步发送,仍在当前线程)。
• NSPostWhenIdle:当 RunLoop 空闲时发送(延迟到线程空闲时异步执行,仍在当前线程)。
示例代码:
// 获取通知队列(与默认通知中心关联)
let queue = NotificationQueue.default
// 创建通知
let notification = Notification(name: NSNotification.Name("MyNotification"), object: nil)
// 异步发送(当前 RunLoop 周期结束后发送)
queue.enqueue(notification, postingStyle: .asap)
方式二:在后台线程异步发送通知
若希望发送通知的操作本身在后台线程执行(避免阻塞主线程),可以将 post 方法的调用放在异步队列中:
// 在后台线程异步发送通知
DispatchQueue.global().async {
NotificationCenter.default.post(name: NSNotification.Name("MyNotification"), object: nil)
}
此时,通知的发送操作在后台线程执行,而观察者的处理方法也会在该后台线程被调用(因为发送线程决定了处理线程)。
补充:若需在指定线程处理通知(如主线程)
如果观察者需要在特定线程(如主线程)处理通知(即使通知在后台线程发送),需在观察者的处理逻辑中手动切换线程:
// 观察者的处理方法
@objc func handleNotification(_ notification: Notification) {
// 切换到主线程处理(若当前不在主线程)
DispatchQueue.main.async {
// 主线程处理逻辑
}
}
总结
• 默认同步发送时,通知的发送线程与接收处理线程一致。
• 异步发送通知可通过 NotificationQueue(控制发送时机)或 DispatchQueue.async(控制发送线程)实现。
• 若需指定线程处理通知,需在观察者的处理方法中手动切换线程。
二.NSNotificationQueue是异步还是同步发送?在哪个线程响应
NSNotificationQueue 的同步/异步特性及响应线程
NSNotificationQueue 的发送行为既可以是同步也可以是异步,取决于其 postingStyle(发送策略);而通知的响应线程(即观察者处理方法的执行线程)与入队通知时所在的线程一致。
1. 三种发送策略的同步/异步区别:
NSNotificationQueue 通过 enqueue(_:postingStyle:) 方法发送通知,postingStyle 决定了发送时机和同步性:
• NSPostNow(立即发送):
同步发送,等价于直接调用 NotificationCenter.post()。入队后会立即触发通知发送,阻塞当前流程直到所有观察者处理完毕。
(本质是“插队”立即执行,不经过队列延迟,属于同步行为。)
• NSPostASAP(尽快发送):
异步延迟发送。通知会被加入队列,等待当前 RunLoop 周期结束时(即当前循环中所有事件处理完毕后)发送。不会阻塞当前流程,属于异步行为。
• NSPostWhenIdle(空闲时发送):
异步延迟发送。通知会被加入队列,等待RunLoop 进入“空闲状态”(即没有任何事件需要处理时,如没有用户交互、定时器、网络事件等)才发送。延迟时间最长,属于异步行为。
2. 响应线程:与入队时的线程一致
NSNotificationQueue 仅负责延迟通知的发送时机,不会改变线程。通知最终发送时的线程,与调用 enqueue 方法时所在的线程一致;因此,观察者的处理方法也会在该线程被调用。
例如:
// 在主线程入队通知(asap 策略)
DispatchQueue.main.async {
let notification = Notification(name: .init("Test"), object: nil)
NotificationQueue.default.enqueue(notification, postingStyle: .asap)
}
// 通知会在主线程的 RunLoop 周期结束后发送,观察者处理方法也在主线程执行。
三、NSNotificationQueue 与 RunLoop 的关系
NSNotificationQueue 本质是依赖 RunLoop 机制实现延迟发送的“通知调度器”,其核心逻辑与 RunLoop 的运行周期紧密绑定。
1. RunLoop 如何触发通知发送?
RunLoop 是线程的事件处理循环,每次循环会处理事件(如 UI 事件、定时器、网络回调等)并在特定阶段检查状态。NSNotificationQueue 会在 RunLoop 的两个关键阶段触发通知发送:
• NSPostASAP 触发时机:
当 RunLoop 完成当前周期的所有事件处理(即将进入“休眠”或“退出”前),会检查队列中 NSPostASAP 策略的通知,批量发送。
• NSPostWhenIdle 触发时机:
当 RunLoop 处理完所有事件后,若处于“空闲”状态(没有新事件需要处理),会检查队列中 NSPostWhenIdle 策略的通知并发送。
2. 为什么需要结合 RunLoop?
NSNotificationQueue 的设计目的是避免短时间内大量通知的频繁发送(如 UI 布局更新、数据频繁变化时),通过 RunLoop 周期“合并”通知,减少处理开销。
例如:当连续多次发送同一通知(如滚动视图的 contentOffset 变化),NSNotificationQueue 会根据策略合并为一次发送(避免重复处理),而合并的时机由 RunLoop 周期决定。
总结
• NSNotificationQueue 的同步/异步取决于发送策略:postNow 是同步,asap 和 whenIdle 是异步。
• 响应线程与入队时的线程一致,不涉及线程切换。
• 与 RunLoop 深度绑定:通过 RunLoop 的周期和空闲状态决定通知的发送时机,实现延迟和合并通知的功能。
四、如何保证通知接收的线程在主线程
通知的接收线程默认与发送线程一致,若需强制在主线程处理,需在观察者的处理逻辑中手动切换线程(通知中心本身不支持直接指定接收线程)。
常见做法:在通知处理方法中,用 DispatchQueue.main.async 包裹具体逻辑,确保在主线程执行:
// 观察者注册通知
NotificationCenter.default.addObserver(self, selector: #selector(handleNotification), name: NSNotification.Name("TestNotification"), object: nil)
// 处理方法中切换到主线程
@objc private func handleNotification(_ notification: Notification) {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return } // 避免循环引用
// 主线程处理逻辑(如更新UI)
self.updateUI()
}
}
原理:无论通知在哪个线程发送,处理逻辑最终会被派发到主线程执行,确保线程安全(尤其适合UI操作)。
五、页面销毁时不移除通知会崩溃吗?
可能会崩溃,核心原因是“野指针访问”:
• 当页面(如 UIViewController)销毁后,若未从通知中心移除观察者,通知中心的观察者列表中仍会保留该页面的引用(如通过 selector 或 block 持有)。
• 当通知发送时,通知中心会尝试调用已销毁对象的方法(或执行已释放对象关联的 block),此时会访问已释放的内存,导致野指针崩溃(EXC_BAD_ACCESS)。
例外情况:若使用 block 注册通知时,block 中未强引用 self(如用 [weak self]),且对象已释放,此时通知中心调用 block 时可能不会崩溃(但逻辑上已无意义)。但这种情况仍不推荐,因为无法保证绝对安全。
结论:页面销毁时必须移除通知,避免崩溃。通常在 deinit(Swift)或 dealloc(OC)中移除。
五、多次添加/移除同一个通知的结果
1. 多次添加同一个通知(相同 name、object、selector/block)
每次添加都会在通知中心的观察者列表中新增一条记录,导致:
• 当通知发送时,观察者的处理方法(selector 或 block)会被多次调用,调用次数等于添加次数。
示例:
// 多次添加同一通知
NotificationCenter.default.addObserver(self, selector: #selector(handle), name: .test, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handle), name: .test, object: nil)
// 发送一次通知
NotificationCenter.default.post(name: .test, object: nil)
// 结果:handle方法会被调用2次
2. 多次移除同一个通知
• 若移除时的参数(name、object)与添加时完全一致:
第一次移除会删除一条观察者记录,第二次移除时若已无对应记录,通知中心会忽略该操作(不会崩溃)。
• 若调用 removeObserver(_ observer: Any)(移除该对象的所有通知):
第一次调用会移除该对象的所有观察者记录,后续再次调用该方法也会被忽略(无副作用)。
示例:
// 添加2次同一通知
NotificationCenter.default.addObserver(self, selector: #selector(handle), name: .test, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(handle), name: .test, object: nil)
// 第一次移除:删除1条记录
NotificationCenter.default.removeObserver(self, name: .test, object: nil)
// 第二次移除:无对应记录,忽略(不会崩溃)
NotificationCenter.default.removeObserver(self, name: .test, object: nil)
// 发送通知:此时仅剩0条记录,handle不会被调用
总结
• 保证主线程接收:在处理方法中用 DispatchQueue.main.async 切换线程。
• 页面销毁不移除通知:大概率崩溃(野指针访问),必须移除。
• 多次添加:处理方法多次执行;多次移除:重复移除无副作用(不会崩溃)。
基础概念
1. 什么是iOS中的通知中心?
答案:iOS中的通知中心(NSNotificationCenter)是一个消息传递机制,允许应用程序中的对象在发生特定事件时发送通知,其他对象可以注册观察这些通知,以便在事件发生时收到通知并作出相应响应。
2. 通知中心的作用是什么?
答案:它实现了对象间的解耦通信。当一个对象的状态发生变化或完成某个任务时,可通过通知中心告知其他感兴趣的对象,而无需了解这些对象的具体信息,使得代码的可维护性和扩展性更好。
3. NSNotification和NSNotificationCenter的关系是什么?
答案:NSNotification是通知对象,包含了通知的名称、发送者和相关的用户信息。NSNotificationCenter是管理通知的中心枢纽,负责添加和移除观察者,以及发送通知。
4. 如何在iOS中注册一个通知观察者?
答案:使用addObserver:selector:name:object:方法。例如:[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleNotification:) name:@"SomeNotificationName" object:nil];
5. 如何在iOS中发送一个通知?
答案:使用postNotificationName:object:userInfo:方法。如[[NSNotificationCenter defaultCenter] postNotificationName:@"SomeNotificationName" object:self userInfo:@{@"key":@"value"}];
通知的传递与接收
6. 通知在传递过程中是同步还是异步的?
答案:默认情况下,通知是在发送线程上同步传递的。如果发送通知的代码在主线程,那么接收通知的方法也会在主线程执行。
7. 如何确保通知在指定的线程上接收?
答案:可以在注册通知观察者时,通过设置NSOperationQueue来指定接收通知的线程。例如[[NSNotificationCenter defaultCenter] addObserverForName:@"SomeNotificationName" object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) { // 处理通知的代码 }];
8. 当一个对象被释放时,它注册的通知观察者会自动移除吗?
答案:不会。需要在对象销毁前手动调用removeObserver:方法来移除通知观察者,否则可能会导致野指针错误。
9. 如何移除一个通知观察者?
答案:使用removeObserver:方法,如[[NSNotificationCenter defaultCenter] removeObserver:self];也可以指定通知名称和发送者来精准移除,[[NSNotificationCenter defaultCenter] removeObserver:self name:@"SomeNotificationName" object:someSender];
10. 可以在多个地方注册观察同一个通知吗?
答案:可以。多个对象可以注册观察同一个通知,当通知发送时,所有注册的观察者都会收到通知并执行相应的方法。
通知的应用场景
11. 请列举一些iOS开发中适合使用通知的场景。
答案:例如界面切换时传递数据,网络状态变化通知,键盘的弹出和隐藏通知,以及应用内不同模块之间的解耦通信等。
12. 在一个复杂的iOS应用中,如何避免通知名称的冲突?
答案:可以使用命名空间来限定通知名称,例如使用应用的Bundle Identifier作为前缀,或者使用类名作为前缀,如com.example.app.SomeNotificationName或MyViewController.SomeNotificationName。
13. 如何在不同的ViewController之间通过通知传递数据?
答案:在发送通知的ViewController中,使用postNotificationName:object:userInfo:方法发送通知并携带数据。在接收通知的ViewController中,在viewDidLoad等方法中注册通知观察者,通过userInfo字典获取传递的数据。
14. 在iOS应用中,如何利用通知来响应设备方向的变化?
答案:可以注册观察UIDeviceOrientationDidChangeNotification通知,当设备方向改变时,通知中心会发送该通知,接收者可以在相应的方法中获取新的设备方向并进行界面调整等操作。
15. 如何使用通知来处理应用的后台和前台切换?
答案:注册观察UIApplicationDidEnterBackgroundNotification和UIApplicationWillEnterForegroundNotification通知,分别在应用进入后台和即将进入前台时收到通知,从而执行相应的资源释放、数据保存或界面更新等操作。
通知与其他技术的结合
16. 通知与KVO(键值观察)有什么区别和联系?
答案:区别在于KVO主要用于观察对象属性的变化,是一种更细粒度的观察机制,而通知用于更广泛的事件通知。联系是它们都是iOS中的消息传递机制,都可以用于实现对象间的通信和响应。
17. 在使用通知和代理模式时,如何选择?
答案:当通信是一对一,且需要明确的协议和方法调用时,适合用代理模式。当通信是一对多,且不关心具体的接收者是谁,只需要广播事件时,适合用通知。
18. 如何在通知中结合使用Block?
答案:可以使用addObserverForName:object:queue:usingBlock:方法注册通知观察者,在Block中处理通知,这样可以更方便地在当前上下文捕获变量,并且代码更紧凑。
19. 通知与NSNotificationCenter在多线程环境下如何保证线程安全?
答案:NSNotificationCenter本身在多线程环境下是线程安全的。但在发送和接收通知时,需要注意对共享资源的访问同步,避免在多个线程同时访问和修改同一资源时出现数据不一致的问题。
20. 如何在Swift中使用通知与Objective - C代码进行交互?
答案:在Swift中可以使用NotificationCenter.default来替代NSNotificationCenter defaultCenter。在与Objective - C代码交互时,要注意通知名称和参数的类型转换,确保Swift和Objective - C代码中使用的通知名称和格式一致。
通知的高级特性
21. 什么是本地通知?它与通知中心有什么关系?
答案:本地通知是在设备本地触发的通知,用于在应用未运行或在后台运行时提醒用户。它与通知中心不同,通知中心主要用于应用内对象间的通信,而本地通知是由系统管理并在合适的时机展示给用户。不过应用可以通过通知中心来接收本地通知被触发的事件。
22. 如何在iOS中设置本地通知?
答案:使用UNUserNotificationCenter类,首先请求用户授权,然后创建UNMutableNotificationContent设置通知内容,再创建UNTimeIntervalNotificationTrigger或其他类型的触发条件,最后使用UNUserNotificationCenter的addNotificationRequest:withCompletionHandler:方法添加通知请求。
23. 本地通知可以设置哪些触发条件?
答案:可以设置基于时间间隔的触发条件UNTimeIntervalNotificationTrigger,基于日历日期的UNCalendarNotificationTrigger,以及基于地理位置的UNLocationNotificationTrigger等。
24. 如何在应用中接收和处理本地通知?
答案:在AppDelegate中实现userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:方法,当应用处于前台或后台时收到本地通知,该方法会被调用,可在此方法中处理通知相关逻辑。
25. 什么是远程通知?它与本地通知有什么区别?
答案:远程通知是由服务器发送到设备的通知。与本地通知的区别在于,远程通知需要通过网络从服务器获取,而本地通知是在设备本地设置和触发的。远程通知可以在应用未安装时也能通过APNS(苹果推送通知服务)推送给用户。
通知的性能与优化
26. 大量发送通知会对应用性能产生什么影响?
答案:大量发送通知可能会导致性能下降,因为通知的传递涉及到方法调用和消息分发,会消耗一定的CPU时间。如果处理通知的代码复杂,还可能导致界面卡顿。
27. 如何优化通知的使用以提高应用性能?
答案:避免不必要的通知发送,只在关键事件发生时发送通知。在处理通知的方法中,尽量减少复杂的操作,将耗时操作放到后台线程执行。同时,及时移除不再需要的通知观察者,避免内存泄漏。
28. 在iOS中,通知的发送和接收是否有性能开销?如何降低这种开销?
答案:有性能开销。降低开销的方法包括减少通知的发送频率,优化通知携带的数据,避免在通知处理方法中进行大量的UI更新操作,尽量在主线程之外处理通知等。
29. 如何检测应用中通知相关的性能问题?
答案:可以使用Xcode的性能分析工具,如Time Profiler来查看通知发送和处理方法的执行时间,分析是否存在性能瓶颈。也可以通过打印日志来记录通知的发送和接收情况,观察是否有异常的频繁发送或处理时间过长的问题。
30. 在多视图控制器的应用中,如何管理通知以避免性能问题?
答案:在视图控制器的viewWillAppear:方法中注册通知,在viewWillDisappear:方法中移除通知,确保只有当前可见的视图控制器才接收通知,减少不必要的通知处理。同时,对于一些全局的通知,可以考虑使用单例模式来管理观察者,避免重复注册。
通知的实际应用案例
31. 假设你正在开发一个聊天应用,如何使用通知来实现新消息提醒?
答案:当收到新消息时,发送一个通知,通知名称可以是NewMessageReceivedNotification。在聊天界面的视图控制器中注册观察该通知,当收到通知后,更新界面显示新消息,如在消息列表中添加新消息,或在导航栏上显示未读消息数量等。
32. 在一个电商应用中,如何利用通知来处理库存变化?
答案:当商品库存发生变化时,例如库存不足或库存更新,相关模块发送通知。在商品详情页和购物车等界面注册观察库存变化通知,当收到通知后,根据库存情况更新界面显示,如将商品的购买按钮置灰或提示库存不足等信息。
33. 在一个音乐播放应用中,如何使用通知来实现音乐播放状态的同步?
答案:音乐播放模块在播放、暂停、切换歌曲等操作时发送相应的通知。在应用的其他界面,如主界面、锁屏界面等注册观察这些通知,根据通知内容更新界面上的音乐播放状态显示,如播放按钮的状态、歌曲信息等,以实现音乐播放状态在不同界面的同步。
34. 在一个地图应用中,如何利用通知来处理位置更新?
答案:位置管理模块在获取到用户位置更新时发送通知。地图界面注册观察位置更新通知,收到通知后更新地图上用户的位置标注,以及根据新位置进行地图缩放和移动等操作,确保地图始终显示用户当前的准确位置。
35. 在一个健身应用中,如何使用通知来记录运动数据?
答案:运动监测模块在运动过程中,如跑步、健身等,实时发送运动数据更新通知,包括运动距离、速度、消耗的卡路里等信息。数据记录模块注册观察这些通知,将收到的数据保存到数据库或本地文件中,以便用户查看运动历史记录和分析运动数据。
通知的安全性与稳定性
36. 如何确保通知在传递过程中的数据安全性?
答案:对通知中携带的敏感数据进行加密处理,在发送和接收端进行数据校验,确保数据的完整性和准确性。同时,限制通知的发送和接收权限,只允许授权的对象发送和接收特定的通知。
37. 在应用更新或系统升级后,通知相关的功能可能会出现哪些问题?如何解决?
答案:可能出现通知注册或发送的方法被废弃,导致功能失效;或者通知的行为发生变化,例如传递的数据格式改变等。解决方法是及时更新代码,根据新的API文档调整通知的使用方式,对可能变化的部分进行兼容性处理,如使用条件编译来适应不同的系统版本。
38. 如何处理通知在发送过程中出现的错误?
答案:可以在发送通知的代码中添加错误处理逻辑,例如使用NSError来捕获可能出现的错误,根据错误类型进行相应的处理,如重新发送通知、提示用户错误信息等。
39. 如何保证通知相关功能在不同设备和系统版本上的稳定性?
答案:在开发过程中,进行全面的设备和系统版本兼容性测试,针对不同设备和系统版本可能出现的问题进行针对性处理。遵循苹果的开发规范和最佳实践,及时更新代码以适应系统的变化。
40. 在多语言环境下,通知相关的文本内容如何进行本地化处理?
答案:将通知中的文本内容提取到本地化字符串文件中,根据用户设备的语言设置,在发送通知时获取相应语言的文本内容进行展示。可以使用NSLocalizedString函数来获取本地化字符串。
通知与应用架构
41. 在MVC架构中,通知通常在哪些部分使用?
答案:在MVC架构中,通知通常在模型层和视图层之间使用。模型层在数据发生变化时发送通知,视图层注册观察这些通知来更新界面显示。例如,当模型层的用户数据更新时,发送通知给视图层,让视图层刷新用户信息展示。
42. 在MVVM架构中,如何通过通知来实现视图和视图模型的交互?
答案:在MVVM架构中,视图模型可以通过发送通知来告知视图数据的变化。视图注册观察这些通知,并根据通知内容更新自身的界面显示。例如,视图模型在获取到新的列表数据后,发送通知给视图,视图接收到通知后更新列表视图的展示。
43. 在iOS应用中,如何将通知相关的代码进行模块化和封装?
答案:可以创建一个通知管理类,将通知的注册、发送和移除等操作封装在该类中。其他模块通过调用该类的方法来使用通知,这样可以提高代码的可维护性和可读性,避免通知相关代码在多个地方分散出现。
44. 在一个大型iOS应用中,如何设计通知的架构以提高可维护性和可扩展性?
答案:可以采用分层架构,将通知分为不同的层次,如系统级通知、业务逻辑级通知和界面级通知。对通知进行分类管理,每个层次有专门的模块负责处理相应的通知。同时,使用接口和协议来规范通知的发送和接收,使得代码更易于扩展和维护。
45. 如何在iOS应用中实现通知的全局监听和局部监听?
答案:对于全局监听,可以在AppDelegate或单例类中注册观察一些全局的通知,如应用状态变化通知。对于局部监听,在需要的视图控制器或模块中注册观察特定的通知,只在当前范围内接收和处理相关通知。
通知与用户体验
46. 如何通过通知来提升用户体验?
答案:通过及时准确地发送通知,让用户了解应用的重要信息和状态变化。例如,在电商应用中通知用户订单状态更新,在社交应用中通知用户新消息和好友请求等,使用户能够及时响应,提高用户对应用的满意度和使用频率。
47. 在设计通知时,如何考虑用户的隐私和打扰问题?
答案:在发送通知前,请求用户授权,让用户可以选择是否接收通知。同时,合理控制通知的发送频率和时间,避免在用户休息或忙碌时发送过多打扰性的通知。对于涉及用户隐私的通知,要确保数据的安全性和保密性。
48. 如何根据用户的行为和偏好来定制通知内容和发送方式?
答案:通过分析用户的使用习惯和历史数据,了解用户的兴趣和偏好。例如,如果用户经常关注某类商品,在发送电商通知时,优先推送该类商品的相关信息。根据用户设置的通知偏好,如声音、震动等方式来发送通知,提高用户对通知的关注度和接受度。
49. 如何在通知中提供便捷的操作入口,以提高用户交互性?
答案:对于本地通知,可以使用UNNotificationAction和UNNotificationCategory来设置通知的操作按钮,用户可以直接在通知上进行操作,如回复消息、删除任务等。对于应用内通知,可以在通知的处理方法中,根据通知内容展示相应的操作界面,方便用户进行下一步操作。
50. 如何通过通知来引导用户进行特定的操作,以提高应用的转化率?
答案:例如在电商应用中,当用户加入购物车但未结算时,发送通知提醒用户完成结算,并提供结算按钮入口。在游戏应用中,通知用户完成每日任务可获得奖励,引导用户进入应用完成任务,通过这种有针对性的通知引导,提高用户完成特定操作的概率,从而提高应用的转化率。