In front of the

When I first learned the code related to NSNotification in Swift, I found that the type of the name parameter I was familiar with was changed from NSString in Objective-C to notification. name. Not exactly the String I expected… What’s going on here?

How do I use Notification in Swift

So, how do you use Notification in Swift? Take POST for example.

NotificationCenter.default.post(name: Notification.Name.UIApplicationDidFinishLaunching, object: nil)
Copy the code

Notification.Name can be omitted

NotificationCenter.default.post(name: .UIApplicationDidFinishLaunching, object: nil)
Copy the code

View definition found UIApplicationDidFinishLaunching is actually defined in structure NSNotification. Name extensions (extension) in a static constants (static let). Type is the NSNotification. Name

extension NSNotification.Name {

    @available(iOS 4.0*),public static let UIApplicationDidEnterBackground: NSNotification.Name

    @available(iOS 4.0*),public static let UIApplicationWillEnterForeground: NSNotification.Name

    public static let UIApplicationDidFinishLaunching: NSNotification.Name. }Copy the code

So we can omit the previous Notification. The Name directly using the UIApplicationDidFinishLaunching (Notification. The Name is NSNotification. Alias Name)

What if we want to customize a notification, just like the system, we can add an extension to it

extension Notification.Name {
	static let LoginStatusChanged = Notification.Name("LoginStatusChanged")}Copy the code

Notification.Name(“LoginStatusChanged”) is the initialization method

NotificationCenter.default.post(name: .LoginStatusChanged, object: nil)
Copy the code

Since the Notification LoginStatusChanged is defined in notification. Name, there is no need to add Notification after the Name to indicate that this is a Notification. So many of the names defined in Swift are very succinct.

Compare the use in Objective-C

Contrast that with the previous use in Objective-C

[[NSNotificationCenter defaultCenter] postNotificationName:"xxxxxxxxxx" object:nil

This is very error-prone, and checking for such errors is often time-consuming and inelegant, so we often use macro definitions or constants to prevent the problem of hard-coding strings.

But this can actually cause some headaches:

  1. To indicate that the defined string constant is a notification name, add a lengthy prefix or suffix to it
  2. It is also common in development to see constant names in code completion that are completely different from the occasion
  3. For ease of use and maintenance, all notifications are defined in a xxdefine.h header file and referenced in the PCH file, if any notifications are added, deleted, or modified. This will cause a full recompilation of the project. Also very headache….

So Swift is a very elegant way to use it.

The lines

In development, there are many other scenarios that require strings to be passed like Notification, which can be optimized using this kind of usage method.

scenario

Consider a scenario where you define a class EventReporter to handle buried requests.

class EventReporter {

	static let shared = EventReporter(a)func reportEvent(_ eventId: String, withParams params: [String:Any]?) {
		// Buried point reporting logic}}Copy the code

EventId is the ID of the event we buried. How can we optimize such a scenario in a way similar to notification. Name?

The principle of

From the documentation, you can see that Notification.Name actually complies with a protocol RawRepresentable

Overview

With a RawRepresentable type, you can switch back and forth between a custom type and an associated RawValue type without losing the value of the original RawRepresentable type. Using the raw value of a conforming type streamlines interoperation with Objective-C and legacy APIs and simplifies conformance to other protocols, such as Equatable, Comparable, and Hashable.

The RawRepresentable protocol is seen mainly in two categories of types: enumerations with raw value types and option sets.

Simply put, RawRepresentable types are used to switch back and forth between a custom type and its associated RawValue type, simplifying interaction with Objective-C and traditional apis. Enumerations with primitive value types and option sets (optionSets, which in Swift are integrated with the Protocol implementation RawRepresentable). It’s just a type that encapsulates the type that we want to use like String to make it easier to interact.

implementation

It is simple to define a structure to manage all of the buried events

struct EventID: RawRepresentable {}Copy the code

Complete the protocol code as prompted by the compiler

struct EventID: RawRepresentable {
	typealias RawValue = String
	
	var rawValue: String
	
	init? (rawValue:String) {}}Copy the code

This makes it easier to see how it works. In fact, the internal rawValue property is the name of the event of type String that we need to use, which the initializer passes in to assign a value to, and returns a structure of type EventID

The initializer for notification. Name is not Optional because it is defined as the event Name (Notification Name). And init method doesn’t raise an exception, so there’s no need to use Optional here, okay? Can be

struct EventID: RawRepresentable {
	typealias RawValue = String
	
	var rawValue: String
	
	init(rawValue: String) {
		self.rawValue = rawValue
	}
}
Copy the code

So, the code for our reporting class could be modified as follows, and we could also give params a default value so that if there are no arguments, we can just pass the eventId argument.

class EventReporter {

	static let shared = EventReporter(a)func reportEvent(_ eventId: EventID, withParams params: [String:Any]? = nil) {
		let event = eventId.rawValue
		// insert logic}}Copy the code

Finally, define a buried event to look at. It is recommended to write in extension for easy maintenance.

extension EventID {
	static let LoginPageExposure = EventID(rawValue: "login_page_exposure")}Copy the code

So when you use it,

EventReporter.shared.reportEvent(.LoginPageExposure)
Copy the code

When we type., the code completion will already prompt LoginPageExposure to us.

conclusion

Optimizing your code this way not only makes the intent of your code easier to understand, but it’s also easier and error-free to use. It also does not cause the LoginPageExposure event name to be forcibly popped by code completion when it is not intended.

Reference

  • NSNotification.Name
  • RawRepresentable