Look at Notification. Name to see how Swift handles String hardcoding elegantly

  • 2020-06-15 10:22:10
  • OfStack

In front of the

When I first learned the NSNotification code in Swift, I noticed that the type of the previously familiar name parameter changed from NSString in ES7en-ES8en to Notification.Name. What's going on here?

How is Notification used in Swift

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


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

Notification.Name


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

Looking at the definition reveals that UIApplicationDidFinishLaunching is actually a static constant (static let) defined in the structure NSNotification.Name extension (extension), of type ES40en.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 Notification.Name and use.UIApplicationDidFinishLaunching (Notification.Name is an alias for NSNotification.Name)

So what if we want to customize a notification, we can just copy the system and add an extension to it


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

Notification. Name("LoginStatusChanged") is its initialization method, which can be viewed in the documentation and used directly


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

Since the notification LoginStatusChanged is defined in ES69en.Name, there is no need to add Notification to indicate that it is a notification. Many definitions in Swift have very concise names.

Compare the use of ES76en-ES77en

Compare the previous use in Objective-C


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

This is very error-prone, and it's often very time-consuming and unelegant to look up, so we often use macro definitions or constants to prevent string hardcoding problems.

But this actually raises a number of headaches:

To indicate that the defined string constant is a notification name, add a verbose prefix or suffix During development, you will often see 1 constant name in code completion that does not exist at all In general, for ease of use and maintenance, all notifications are defined in 1 ES91en.h header file and referenced in pch file. If any notifications are added, deleted, or modified, it will cause a complete recompilation of the project.
...

So Swift is 10 points of elegance to use.

Take 1 3

In development, there are many scenarios like Notification where you need to pass a string, and you can use this usage for optimization.

scenario

Suppose you have a scenario where you define a class EventReporter to handle bury point requests.


class EventReporter {

 static let shared = EventReporter()

 func reportEvent(_ eventId: String, withParams params: [String:Any]?) {
 //  Embedding escalation logic 
 }
}

I believe that many people have seen this scenario, where eventId is the ID of the events we bury, so how can we optimize this scenario in a way similar to ES118en. Name?

The principle of

It is clear from the documentation that ES126en. Name actually complies with one 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, using the RawRepresentable type, you can switch back and forth between a custom type and its associated RawValue type, simplifying interactions with es142EN-ES143en and traditional API. There are two types: Enumeration with primitive value types and option sets (OptionSet, Swift is integrated from RawRepresentable), which is to use one type to encapsulate the type we want to use, such as String, for easy interaction.

implementation

It is simple to use, defining a structure to manage all buried point events


struct EventID: RawRepresentable {
 
}

According to the compiler prompt, complete the protocol code


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

This makes it easier to see how it works. In fact, the internal rawValue attribute is the event name of type String that we need to use. The initializer method passes in the String and assigns it, returning the structure of type EventID

Here find initialization method returns a Optional type, such use still need to unpack, not too convenient, you can see Notification. Not Optional Name initialization method returns, because the definition is very sure of the event name (notice), and also won't produce abnormal init method, so no need to use Optional here, remove the & # 63; Can be


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

Then, the code for our escalation class can be modified as follows, and params 1 can be given a default value, so that if there are no arguments, eventId 1 can be passed.


NotificationCenter.default.post(name: .UIApplicationDidFinishLaunching, object: nil)
0

Finally, define a bury point event, which is recommended for easy maintenance in extension.


NotificationCenter.default.post(name: .UIApplicationDidFinishLaunching, object: nil)
1

So when you use it,


NotificationCenter.default.post(name: .UIApplicationDidFinishLaunching, object: nil)
2

The code completion prompts us for LoginPageExposure when we type.

conclusion

Optimizing the code in this way not only makes it easier to understand the intent of the code, but also makes it easier to use error-free. It also prevents the LoginPageExposure event name from being forced out by code completion when it is not intended.

Reference

NSNotification.Name RawRepresentable

Related articles: