SoFunction
Updated on 2025-04-07

By seeing how Swift solves String hardcoded

Front

When I was about to learn the relevant NSNotification code in Swift, I found that the type of the name parameter that I was familiar with before changed from NSString in Objective-C to a type. It is not the String type I expected... What's going on?

How to use Notification in Swift

So, how to use Notification in Swift, take post as an example.

(name: , object: nil)

Among them, it can be omitted, and it becomes

(name: .UIApplicationDidFinishLaunching, object: nil)

Looking at the definition, I found that UIApplicationDidFinishLaunching is actually a static constant (static let) defined in the structure extension, and the type is

extension  {

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

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

 public static let UIApplicationDidFinishLaunching: 
 ...
}

Copy the code so we can omit the previous one and use .UIApplicationDidFinishLaunching (yes alias)

So what should we do if we want to customize a notification? We can directly imitate the system method and add an extension to it ourselves.

extension  {
 static let LoginStatusChanged = ("LoginStatusChanged")
}

Where ("LoginStatusChanged") is its initialization method, you can view the document description, and when used, you can directly

(name: .LoginStatusChanged, object: nil)

Because this notification LoginStatusChanged is defined in , there is no need to add Notification and other words after the name to indicate that this is a notification. Therefore, many of the names defined in Swift are very concise.

Comparison of usage in Objective-C

Compare the previous use in Objective-C

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

This is very easy to make mistakes, and checking such errors is often time-consuming and laborious, and it also seems very inelegant. Therefore, we often use macro definitions or constants to prevent the problem of hard-coded strings.

But this actually causes some headaches:

  • To indicate that the defined string constant is a notification name, it must also be added with a lengthy prefix or suffix.
  • During development, I often see some constant names that are not in harmony with the situation.
  • Usually, for the convenience of use and easy to maintain, all notifications are defined in a header file and referenced in the pch file. If any notification is added or deleted or modified at this time, it will cause full recompilation of the project. It is also a headache.
    ...

Therefore, Swift is used in a very elegant way.

learn by analogy

In development, there are actually many scenarios similar to Notification that require passing strings, and we can use this kind of usage method to optimize.

Scene

Suppose there is such a scenario, defining a class EventReporter to handle buried point requests.

class EventReporter {

 static let shared = EventReporter()

 func reportEvent(_ eventId: String, withParams params: [String:Any]?) {
 // Buried point reporting logic }
}

I believe that many people have seen such a scenario. The eventId is the ID of the event we buried. So how can we use a similar method to optimize this scenario?

principle

It can be seen from the documentation that it is actually following a protocol.

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, which can simplify interaction with Objective-C and traditional APIs. There are two types: enumerations with primitive value types and option sets (OptionSet, in fact, the option set enumeration in Swift is integrated from the RawRepresentable Protocol). To put it bluntly. It is to use a type to encapsulate the type we want to use, such as String, to facilitate interaction.

accomplish

It's easy to use, define a structure to manage all 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) {
 
 }
}

It is easier to see its principle from this. In fact, the internal rawValue property is the event name of the String type we need to use. The initialization method can be passed into the String and assign a value to it, and returns the structure of the EventID type

Here I found that the initialization method returns an Optional type, which requires unpacking when used, which is not very convenient. You can see that the initialization method returns not Optional, because the definitions are very certain event names (notification names), and there is no exception in the init method, so there is no need to use Optional here, just remove it?

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

Then, the code of our reporting class can be modified as follows. Here you can also give params a default value, so that if there is no parameter, you can only pass one parameter of eventId.

class EventReporter {

 static let shared = EventReporter()

 func reportEvent(_ eventId: EventID, withParams params: [String:Any]? = nil) {
 let event = 
 // Point logic }
}

Finally, define a buried event and take a look~. It is recommended to write it in extension for easy maintenance.

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

Then when using it,

(.LoginPageExposure)

When we typed . , the code completion prompted us with LoginPageExposure.

Summarize

Optimizing the code in this way will not only make the code intention easier to understand, but also make use easier and without errors. It will also not cause the LoginPageExposure event name to be forced to pop up by the code completion function when it does not want it to appear.

Okay, the above is the entire content of this article. I hope that the content of this article has a certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.

Reference

  • RawRepresentable