Because the team hope project to CoreData, whereas in the past are all dependent on CoreData NSFetchedResultsController state synchronization. CoreData must therefore be removed to find an alternative to state synchronization.

NotificationCenter

State synchronization is actually a one-to-many scenario, where an event can be listened to by multiple observers. The NotificationCenter of Apple’s system framework is used to adapt to this scenario, and it is also widely used by the system framework itself and our developers. Usage:

  1. Define the notification name, as well as the key that needs to pass additional information
  2. Register notifications based on target-action
open func addObserver(_observer: Any, selector aSelector: Selector, name aName: NSNotification.Name? , object anObject: Any?)
Copy the code
  1. Implement methods to listen for notifications
func onReceivedNotification(note: NSNotification)
Copy the code
  1. To send a notification, you can pass the object that sent the notification along with some additional information (userInfo)
open func post(name aName: NSNotification.Name, object anObject: Any? , userInfo aUserInfo: [AnyHashable : Any]? =nil)
Copy the code
  1. Notification of removal of registration
open func removeObserver(_observer: Any, name aName: NSNotification.Name? , object anObject: Any?)
Copy the code

Of course, NotificationCenter also provides a more convenient block-based way to register listening for notifications by combining the 2,3 steps into one step.

open func addObserver(forName name: NSNotification.Name? , object obj: Any? , queue: OperationQueue? , using block: @escaping(Notification) -> Void) - >NSObjectProtocol
Copy the code

The overall process is clear and easy to use, but has a serious drawback — weak typing. What we receive is an NSNotification object.

open class NSNotification : NSObject.NSCopying.NSCoding {
    open var name: NSNotification.Name { get }
    open var object: Any? { get }
    open var userInfo: [AnyHashable : Any]? { get}}Copy the code

Suppose we need to convey a message about a state change, we need to include the state of the changed state and the ID of the person being followed. So we need to fetch the desired value from userInfo:

letfollowing = notification.userInfo? ["FollowingKey"] as! NSNumber
letuserID = notification.userInfo? ["UserIDKey"] as! NSNumber;
Copy the code

That is, the receiving party usually needs to look at the document to know how to value from userInfo and what type of value to take. This is extremely inconvenient to use.

SwiftNotificationCenter

SwiftNotificationCenter is a protocol-oriented notification center solution. The usage is as follows:

  1. Define the agreement
protocol FollowingChanged {
    func followingDidChange(following: Bool, userID: NSNumber)
}
Copy the code
  1. Register notifications based on protocol
Broadcaster.register(FollowingChanged.self, observer: observer)
Copy the code
  1. Implementation protocol method
extension ViewController: FollowingChanged {
  func followingDidChange(following: Bool, userID: NSNumber) {
    // do something}}Copy the code
  1. Send a notification
Broadcaster.notify(FollowingChanged.self) {$0.followingDidChange(following, userID)
}
Copy the code
  1. Notification of removal of registration
Broadcaster.unregister(FollowingChanged.self, observer: observer)
Copy the code

We can see that its protocol-based approach solves the problem of weak typing, but it also has the problem of poor scalability.

It is still the scene of changing concerns. If, with the development of business, some places need to know whether they are in the state of mutual correlation after concern, then a field needs to be added to identify them. So we need to modify the protocol to add the parameter followingEachOther, and since it is not a mandatory parameter, it is of optional type.

protocol FollowingChanged {
    func followingDidChange(following: Bool, userID: NSNumber, followingEachOther: NSNumber?)
}
Copy the code

This is especially true in scenarios where this type of notification is widely used. This, too, is clearly unacceptable.

EventBus

EventBus is widely used in Android, and the process is shown below:

EventBus

The usage is as follows:

  1. Define events
 class TPFollowingChangedEvent: NSObject.TPEvent {
    	private(set) var following: Bool
   		private(set) var userID: NSNumber
}
Copy the code
  1. Register event
TPEventBus<TPFollowingChangedEvent>.shared.register(eventType: TPFollowingChangedEvent.self, subscriber: self, selector: #selector(onEvent(event:object:)))
Copy the code
  1. Methods to implement listening events
@objc func onEvent(event: TPFollowingChangedEvent, object: Any?) {
    	// do something
}
Copy the code
  1. Send the event
TPEventBus.shared.post(event: event, object: self)
Copy the code
  1. Removes the registration of events
TPEventBus<TPFollowingChangedEvent>.shared.unregister(eventType: TPFollowingChangedEvent.self, subscriber: self)
Copy the code

As you can see, EventBus is also strongly typed.

If it is still a concerned scenario and you need to know the status of interrelation, then we just need to add the followingEachOther property in TPFollowingChangedEvent. As follows:

class TPFollowingChangedEvent: NSObject.TPEvent {
    	private(set) var following: Bool
   		private(set) var userID: NSNumber
    	private(set) var followingEachOther: NSNumber?
}
Copy the code

Therefore, the following requirements were implemented using EventBus:

  • Strongly typed
  • extensible

EventBus and NotificationCenter are both target-action based schemes, but it is not difficult to extend it to support block listening and also to automatically remove event registration. This is similar to the following:

TPEventBus<TPFollowingChangedEvent>.shared.subscribe(eventType: TPFollowingChangedEvent.self).forObject(self).onQueue(OperationQueue.main).onEvent { (event, object) in
     // do something
}.disposed(by: self.tp_eventTokenBag)
Copy the code

Here I implemented a small but comprehensive EventBus for your reference: TPEventBus.

The last

As we can see, the application flow of the observer mode in one-to-many scenarios is much the same, but it is worth thinking about how to use it better. Of course, the above is just my thinking in some use scenarios, will certainly lack of consideration, welcome to clap brick 😊.