MST

星途 面试题库

面试题:Objective-C通知中心的通知传递过程及性能考量

详细阐述Objective-C通知中心从发送通知到观察者接收到通知的整个过程。同时,分析在大规模使用通知中心机制时可能会遇到哪些性能问题,以及如何优化。
11.0万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

1. 从发送通知到观察者接收到通知的过程

  1. 注册观察者
    • 观察者(通常是某个对象)通过NSNotificationCenteraddObserver:selector:name:object:方法进行注册。
    • 例如:
[[NSNotificationCenter defaultCenter] addObserver:self 
                                         selector:@selector(handleNotification:) 
                                             name:@"SomeNotificationName" 
                                           object:nil];
- 这里`self`是观察者对象,`handleNotification:`是观察者收到通知后要执行的方法,`@"SomeNotificationName"`是通知的名称,`nil`表示可以接收任何对象发送的该名称通知。若指定了`object`,则只有该`object`发送的通知才会被接收。

2. 发送通知 - 发送者通过NSNotificationCenterpostNotificationName:object:userInfo:方法发送通知。 - 例如:

NSDictionary *userInfo = @{@"key": @"value"};
[[NSNotificationCenter defaultCenter] postNotificationName:@"SomeNotificationName" 
                                                      object:self 
                                                    userInfo:userInfo];
- `postNotificationName:`指定通知名称,`object`为发送者对象,`userInfo`是一个可选的字典,用于携带额外信息。

3. 通知中心处理 - NSNotificationCenter维护了一个观察者列表,当接收到postNotificationName:object:userInfo:方法调用时,它会遍历列表,查找所有注册了该通知名称且满足object条件(若有指定)的观察者。 - 对于找到的每个观察者,通知中心会在合适的线程(通常是发送通知所在的线程)上调用观察者注册时指定的选择器方法,并将通知对象作为参数传递。通知对象NSNotification包含了通知名称、发送者对象以及userInfo字典。 4. 观察者接收通知 - 观察者的选择器方法被调用,在方法实现中可以从通知对象获取相关信息并进行处理。 - 例如:

- (void)handleNotification:(NSNotification *)notification {
    NSDictionary *userInfo = notification.userInfo;
    // 处理userInfo中的数据
}

2. 大规模使用通知中心机制时的性能问题

  1. 通知发送的性能开销
    • 每次发送通知时,通知中心都需要遍历所有观察者列表来查找匹配的观察者。随着观察者数量的增加,遍历的时间复杂度呈线性增长,这会导致发送通知的性能开销增大。
  2. 内存管理问题
    • 如果观察者在注册后没有及时注销(通过removeObserver:方法),可能会导致内存泄漏。特别是在观察者对象生命周期结束但仍在通知中心的观察者列表中时,会造成内存无法释放。
  3. 线程安全问题
    • 由于通知可能在不同线程发送和接收,若处理不当,可能会引发线程安全问题。例如,在多线程环境下,对共享资源的访问可能导致数据不一致。
  4. 过多的通知名称
    • 当项目中有大量不同名称的通知时,代码维护变得困难,并且可能因为通知名称冲突等问题导致意外行为。

3. 优化措施

  1. 减少不必要的通知发送
    • 仔细评估通知发送的场景,避免在不必要的情况下发送通知。例如,只在状态真正发生改变且需要通知其他对象时才发送。
  2. 优化观察者管理
    • 确保观察者在不再需要接收通知时及时注销。可以在dealloc方法中添加removeObserver:调用。
    • 例如:
- (void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}
  1. 线程安全处理
    • 若通知处理涉及共享资源,使用锁(如NSLockdispatch_semaphore等)或GCD队列来保证线程安全。例如,使用GCD的串行队列来处理通知,确保对共享资源的访问是串行的。
dispatch_queue_t queue = dispatch_queue_create("com.example.notificationQueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    // 处理通知相关的共享资源操作
});
  1. 通知名称管理
    • 使用常量来定义通知名称,避免硬编码字符串,减少名称冲突的可能性。同时,可以将相关的通知名称定义在一个单独的头文件中,方便管理和维护。
// NotificationConstants.h
FOUNDATION_EXPORT NSString *const SomeNotificationName;

// NotificationConstants.m
NSString *const SomeNotificationName = @"SomeNotificationName";