Mastering macOS Programming
上QQ阅读APP看书,第一时间看更新

Making constants with an enum

Here's a really good use for enum: We can use enum to create a restricted subset of some type, much as we did with the preceding  Coordinate  enum.

For example, when we are defining HTTP request code, we don't want any typing mistakes to find their way into our String objects, rendering the keys (silently) unusable.

A common solution is to create a list of constant strings like so:

let kUserName = "userName" 
let kPassword = "password"
let kvideoPath = "/video"

And so on.

The prefix k indicates that this constant is used as a key for something, perhaps a Dictionary destined for passing to an HTTP request body. This is not dictated by the syntax, it is just a widely-used convention.

But these keys can still get mixed up, since they are simply String objects, and so the compiler cannot check that we are passing the right strings. Any String will keep the compiler happy.

By using an enum, we can gather together any number of String objects under one type:

enum APIKey: String 
{
case userName, password, email
}
Remember that Swift automatically assigns raw String values to enum cases that are declared to be of type String, as discussed previously.

Now when we need to specify method parameter types, and any other type-related definitions, we can use the APIKey type instead of the String type, thereby ensuring that the string "/video" can never be passed as an API key--the compiler will complain (and refuse to compile, of course).

In our data layer, far away on the other side of the program, we may declare something like the following:

typealias APIParams = [APIKey: String] 

And now we can't mess up assigning one of the valid strings to anything declared to be of type APIKey:

let userCredentials: APIParams = [.userName: "Ali Baba", 
.password: "Open Sesame",
.email: "notinvented@themoment"]

Back in the HTTP service layer, we can then safely extract the String values from the APIKey typed values:

var httpParameters: [String: String] = [:] 
for apiKey in userCredentials.keys
{
httpParameters[apiKey.rawValue] = userCredentials[apiKey]
}

This leads to significantly safer code when passing strings around, strings that would otherwise happily compile and lead to complete confusion when the HTTP request comes back with the following error message:

"What??"