likes
comments
collection
share

NSNotification相关

作者站长头像
站长
· 阅读数 2

NSNotification实现原理(结构设计、通知如何存储的、name&observer&SEL之间的关系等)

NSNotification是iOS中用于实现消息通知的类,它采用了观察者模式来实现跨层传递消息。NSNotification的实现原理涉及到NSNotification、NSNotificationCenter、Observation和NCTable这几个主要类和结构体。

  1. NSNotification NSNotification是用于向其他对象发送通知的类,它包含了一些必要的信息,包括通知的名称、发送通知的对象和可选的用户信息。NSNotification对象是不可变的,一旦创建就不能修改。[1]

  2. NSNotificationCenter NSNotificationCenter是NSNotification的管理类,它是一个单例对象。它负责管理所有的NSNotification对象,并将它们发送给对应的观察者。NSNotificationCenter内部维护了一个NCTable结构体,用于存储观察者和通知之间的关系。[1]

  3. Observation和NCTable Observation是一个结构体,用于封装观察者和观察者的方法。它包含了观察者对象、方法选择器、下一个Observation节点的指针等信息。NCTable是一个结构体,用于存储Observation对象。它包含了一个全局的对象表NCTable,其中包含了wildcard、nameless和named等字段,分别用于存储没有通知名称和对象的通知、没有通知名称但有对象的通知,以及有通知名称和对象的通知。[1]

  4. name、observer和SEL之间的关系 在NSNotification的实现中,name和Observation是映射关系。name和observer都包含在Observation结构体中,通过NCTable中的hash表来建立它们之间的关系。具体来说,nameless表中的hash表的key是object参数,value是Observation结构体;named表中的hash表的key是name参数,value是另一个hash表,这个hash表的key是object参数,value是Observation结构体。通过这种方式,NSNotification实现了name、observer和SEL之间的关系。[1]


Learn more:

  1. iOS进阶之NSNotification的实现原理 - 简书
  2. iOS开发 - NSNotification原理理解 | 幸运四叶草
  3. iOS NSNotification实现原理 - 简书

通知的发送是同步的,还是异步的

通知的发送是同步的。

在iOS中,通知的发送是同步的操作。当调用postNotification:方法发送通知时,该方法会立即将通知发送给所有注册的观察者,并等待观察者完成对通知的处理后才会继续执行发送通知的代码。

这意味着在发送通知的过程中,发送通知的线程会被阻塞,直到所有观察者都接收到并处理完通知。这种同步的发送方式可以确保通知的可靠传递和处理顺序的一致性。

需要注意的是,通知的接收和处理是异步的。当观察者接收到通知时,它会在自己的线程中异步处理通知,以避免阻塞主线程或其他线程的执行。

总结起来,通知的发送是同步的,发送通知的线程会被阻塞直到所有观察者接收并处理完通知。而通知的接收和处理是异步的,观察者会在自己的线程中异步处理通知。

NSNotificationCenter接受消息和发送消息是在一个线程里吗?如何异步发送消息

NSNotificationCenter的消息接收和发送是在同一个线程中进行的。

当调用postNotification:方法发送通知时,通知会立即发送给所有注册的观察者,并且发送通知的线程会被阻塞,直到所有观察者都接收并处理完通知。这意味着通知的发送和观察者的处理是在同一个线程中进行的。

如果你希望异步发送消息,可以使用postNotificationName:object:userInfo:方法,并结合GCD(Grand Central Dispatch)来实现异步操作。具体步骤如下:

  1. 创建一个自定义的队列,用于执行异步操作。可以使用dispatch_queue_create函数创建一个串行队列或并发队列。

  2. 在自定义队列中使用dispatch_async函数来执行发送通知的操作。将postNotificationName:object:userInfo:方法放在dispatch_async的block中,以确保在异步队列中执行。

示例代码如下:

// 创建一个自定义队列
let customQueue = DispatchQueue(label: "com.example.notificationQueue")

// 在自定义队列中异步发送通知
customQueue.async {
    NotificationCenter.default.post(name: NSNotification.Name("CustomNotification"), object: nil, userInfo: nil)
}

通过将发送通知的操作放在自定义队列中的异步任务中,可以实现异步发送消息的效果。这样发送通知的操作将不会阻塞当前线程,而是在后台线程中执行。

需要注意的是,接收通知的观察者的处理仍然是在通知所在的线程中进行的。如果你希望观察者的处理也是在异步线程中进行,可以在观察者的处理代码中使用GCD来实现异步操作。

NSNotificationQueue是异步还是同步发送?在哪个线程响应

NSNotificationQueue是同步发送通知的。

NSNotificationQueue是一个用于管理通知的队列,它可以按照指定的顺序发送通知。当调用NSNotificationQueue的enqueueNotification:postingStyle:方法发送通知时,通知会被立即发送,并且发送通知的线程会被阻塞,直到所有观察者都接收并处理完通知。

通知的接收和处理是在通知所在的线程中进行的。如果通知是在主线程中发送的,那么观察者也会在主线程中接收和处理通知。如果通知是在其他线程中发送的,那么观察者也会在相应的线程中接收和处理通知。

需要注意的是,NSNotificationQueue并不是常用的通知发送方式,通常更常用的是直接使用NSNotificationCenter的postNotification:方法来发送通知。而NSNotificationCenter的通知发送是同步的,会阻塞当前线程直到所有观察者接收并处理完通知。

总结起来,NSNotificationQueue是同步发送通知的,发送通知的线程会被阻塞直到所有观察者接收并处理完通知。通知的接收和处理是在通知所在的线程中进行的。

NSNotificationQueue和runloop的关系

NSNotificationQueue和RunLoop之间有一定的关系。

NSNotificationQueue是用于管理通知的队列,它可以按照指定的顺序发送通知。而RunLoop是iOS中用于处理事件和定时器的机制。

NSNotificationQueue可以将通知添加到RunLoop中,以便在特定的运行循环模式下发送通知。通过调用NSNotificationQueue的enqueueNotification:postingStyle:方法,并指定postingStyle为NSPostWhenIdle或NSPostASAP,可以将通知添加到RunLoop中,并在运行循环空闲或尽快时发送通知。

当RunLoop处于运行状态时,它会不断地检查是否有待处理的事件或通知。如果有待处理的通知在RunLoop中,RunLoop会将通知发送给相应的观察者,并在观察者的线程中处理通知。

需要注意的是,NSNotificationQueue并不依赖于RunLoop来发送通知。即使没有RunLoop,NSNotificationQueue仍然可以发送通知,只是通知的发送不会受到RunLoop的调度和控制。

总结起来,NSNotificationQueue可以将通知添加到RunLoop中,并在特定的运行循环模式下发送通知。RunLoop会在运行循环中检查并处理待处理的通知,并将通知发送给相应的观察者。但NSNotificationQueue并不依赖于RunLoop来发送通知,它可以独立地发送通知。

如何保证通知接收的线程在主线程

要确保通知接收的线程在主线程中,可以使用以下方法:

  1. 在注册观察者时,指定观察者方法执行的队列为主队列。可以使用NotificationCenteraddObserver(forName:object:queue:using:)方法来注册观察者,并将queue参数设置为OperationQueue.main,这样观察者方法就会在主线程中执行。
NotificationCenter.default.addObserver(forName: NSNotification.Name("NotificationName"), object: nil, queue: OperationQueue.main) { notification in
    // 在主线程中处理通知
    // ...
}
  1. 在发送通知时,确保在主线程中发送。可以使用DispatchQueue.main.async来将发送通知的操作放在主队列中执行。
DispatchQueue.main.async {
    NotificationCenter.default.post(name: NSNotification.Name("NotificationName"), object: nil)
}

通过以上两种方式,可以确保通知的接收和处理都在主线程中进行。这样可以避免在观察者方法中进行UI更新或其他需要在主线程执行的操作时出现线程不一致的问题。

需要注意的是,如果通知是在其他线程中发送的,观察者方法仍然会在主线程中执行。这是因为在注册观察者时指定了观察者方法执行的队列为主队列。

页面销毁时不移除通知会崩溃吗

iOS页面销毁时不移除通知可能会导致一些问题,但不一定会导致崩溃。

当一个页面被销毁时,如果该页面仍然注册了通知观察者但没有及时移除,那么当通知被发送时,观察者方法仍然会被调用。这可能导致以下问题:

  1. 野指针访问:如果在页面销毁后,通知触发了已被销毁的页面的观察者方法,而该方法中访问了已被释放的对象,就会导致野指针访问,可能引发崩溃。

  2. 内存泄漏:如果页面销毁后,通知触发了已被销毁的页面的观察者方法,而该方法中持有了其他对象的强引用,就会导致内存泄漏,因为这些对象无法被释放。

为了避免这些问题,通常建议在页面销毁时移除通知的观察者。可以在页面的deinit方法中调用NotificationCenterremoveObserver(_:name:object:)方法,将观察者从通知中心中移除。

deinit {
    NotificationCenter.default.removeObserver(self)
}

这样,在页面销毁时,通知触发时就不会再调用已被销毁的页面的观察者方法,从而避免了潜在的问题。

虽然不移除通知可能会导致问题,但不一定会导致崩溃。具体是否会导致崩溃取决于观察者方法中的具体实现和触发通知的时机。为了保证代码的健壮性和可靠性,建议在页面销毁时始终移除通知的观察者。

多次添加同一个通知会是什么结果?多次移除通知呢

When the same notification is added multiple times in iOS, the result depends on how the notification is registered and handled. Here are the possible outcomes:

  1. Multiple notifications are received: If the same notification is added multiple times without removing it, the observer method associated with the notification will be called multiple times when the notification is posted. This can result in the observer method being executed multiple times, leading to duplicated actions or behavior.

  2. No additional effect: In some cases, adding the same notification multiple times may not have any additional effect. The notification system in iOS is designed to handle multiple registrations for the same notification without causing any issues. In this case, the observer method will still be called only once when the notification is posted.

It's important to note that adding the same notification multiple times can lead to unexpected behavior and should generally be avoided. It's recommended to register the notification observer only once and remove it when it's no longer needed.

When it comes to removing notifications, the same principles apply:

  1. Removing the notification once: If the notification observer is removed once using the removeObserver(_:name:object:) method, the observer will no longer receive any notifications for that specific name and object combination.

  2. Removing the notification multiple times: Removing the same notification multiple times does not have any additional effect. Once the observer is removed, it will no longer receive notifications for that specific name and object combination, regardless of how many times the removal is called.

To ensure proper handling of notifications, it's recommended to remove the observer when it's no longer needed, such as when the associated object or view controller is deallocated.


Learn more:

  1. Double Notifications on iPhone - Apple Community
  2. Receiving duplicate push notificat… | Apple Developer Forums
  3. ios - Adding the same observer multiple times without removing it - Stack Overflow