[IOS] Swift beginner's Manual: optional type (Optionals)
A few weeks ago (Translator's note: the original article was published in June 24), Apple released a brand new programming language: Swift. Since then, I have been reading the official Swift manual and reading the Xcode6 betaPlayingLearning. I began to like Swift's conciseness and syntax. I learned this brand new language with my team and compared it with the Objective-C old guy with 30 years of history. At the same time, we are also trying to explore how to make it easy for beginners to master Swift.
Two weeks ago, we released the basic Swift tutorial. In the next few weeks, we will write a series of tutorials to introduce the new features of Swift. This week, let's look at the optional type (Optionals ).
Overview
In the previous tutorial, I mentioned the concept of the optional type, but I did not explain it in detail.
So what is an optional type?
In Swift, when we declare a variable, it is non-optional by default, that is, you must specify a value not nil. If you want to set a non-optional variable to nil, the compiler will tell you: "Hey, you can't set it to nil ". That's right:
var message: String = Swift is awesome! // OKmessage = nil // compile-time error
Of course, the error message provided by the compiler is not so friendly.Could not find an overload for ‘__conversion’ that accepts the supplied arguments
This error occurs. Similarly, the variables declared in the class are optional by default:
class Messenger { var message1: String = Swift is awesome! // OK var message2: String // compile-time error}
Inmessage2
You will get a compilation error because it has no initial value. It may be surprising to those friends who are coming along the way from Objective-C. In Objective-C, this is not a problem at all:
NSString *message = @Objective-C will never die!;message = nil;class Messenger { NSString *message1 = @Objective will never die!; NSString *message2;}
However, you can declare an uninitialized variable in Swift. Swift provides an optional type to indicate no value. You only need to add a question mark after the declared type?
You can:
class Messenger { var message1: String = Swift is awesome! // OK var message2: String? // OK}
You can also assign values to optional types of variables. If no value is assigned, the value is automatically set to nil.
Reason
Why is it designed like this? Apple officially explained that Swift is a secure language. As shown in the preceding example, the optional types of Swift are compiled to prevent some common runtime errors. Let's take a look at the example below for better understanding.
For example, the following code is available in Objective-C:
- (NSString *)findStockCode:(NSString *)company { if ([company isEqualToString:@Apple]) { return @AAPL; } else if ([company isEqualToString:@Google]) { return @GOOG; } return nil;}
In the above method, you can usefindStockCode
Method to obtain the stock code. Obviously, only Apple and Google queries will return the value, and nil will be returned in other cases.
Suppose we will call this method in the following code:
NSString *stockCode = [self findStockCode:@Facebook]; // nil is returnedNSString *text = @Stock Code - ;NSString *message = [text stringByAppendingString:stockCode]; // runtime errorNSLog(@%@, message);
This Code does not have any problems during compilation, But if you enter Facbook, nil will be returned, resulting in a runtime error.
In Swift, errors are not required during running. Swift will prompt an error message during compilation. We can rewrite the above Code in Swift:
func findStockCode(company: String) -> String? { if (company == Apple) { return AAPL } else if (company == Google) { return GOOG } return nil}var stockCode:String? = findStockCode(Facebook)let text = Stock Code - let message = text + stockCode // compile-time errorprintln(message)
In the above Code,stockCode
Is defined as an optional type, which means it can have a string value or nil. If the Code cannot be compiled, an error is prompted:value of optional type String? is not unwrapped
.
As you can see in the example, the optional types of Swift enhance nil detection and provide developers with the check during compilation. reasonable use of the optional types can effectively improve the code quality.
Force resolution
Slow and slow. I have mentioned many advantages, but the Code has not been compiled! Don't worry, we need to check.stockCode
If it is nil or not, modify the Code as follows:
var stockCode:String? = findStockCode(Facebook)let text = Stock Code - if stockCode { let message = text + stockCode! println(message)}
Similar to Objective-C, we first check it to see if it has a value. If it is not nil, we can add an exclamation point!
Then Xcode will know: "Well, I can use this value ". In Swift, we call it forced resolution (forced unwrapping) and use an exclamation point to forcibly obtain the true values of the optional types.
Return to the above Code. We checked to see if the variable is nil before force resolution. This is no different from the common nil detection in Objective-C. What if I forget to check? See the following code:
var stockCode:String? = findStockCode(Facebook)let text = Stock Code - let message = text + stockCode! // runtime error
In this way, we will not get compilation errors, because we use forced resolution, and the compiler has assumed that this optional type must have a value. Obviously, this is an error. The following error occurs during running:
fatal error: Can’t unwrap Optional.None
Optional binding
In addition to forced resolution, optional binding is a more recommended resolution solution. You can use optional binding to check whether a value of an optional type has a value. If there is a value, it is parsed and stored in a temporary variable.
Put the code here! Let's take a look at the following sample code using the optional binding:
var stockCode:String? = findStockCode(Facebook)let text = Stock Code - if let tempStockCode = stockCode { let message = text + tempStockCode println(message)}
In the codeif let
(Orif var
) Is two Optional keywords. Translated into human language, probably like this: "IfstackCode
It has a value and stores its valuetempStackCode
And then continue to execute the following code block. If it has no value, skip the subsequent code block ." BecausetempStockCode
Is a new constant, So you no longer need to add!
Suffix.
You can put the method call inif
So the code looks more concise:
let text = Stock Code - if var stockCode = findStockCode(Apple) { let message = text + stockCode println(message)}
Here,stockCode
It is no longer an optional type and can be used directly. IffindStockCode
If nil is returned by the method, the code block following it will be skipped.
Optional chain
Before interpreting the optional chain, we must make some minor modifications to the original code. We create a new class calledStock
, It hascode
Andprice
Two optional types of attributes.findStockCode
Function is used to returnStock
Object instead ofString
Object:
class Stock { var code: String? var price: Double? }func findStockCode(company: String) -> Stock? { if (company == Apple) { let aapl: Stock = Stock() aapl.code = AAPL aapl.price = 90.32 return aapl } else if (company == Google) { let goog: Stock = Stock() goog.code = GOOG goog.price = 556.36 return goog } return nil}
Next, we usefindStockCode
The function looks up the stock code and then calculates the total price required for purchasing 100 shares:
if let stock = findStockCode(Apple) { if let sharePrice = stock.price { let totalCost = sharePrice * 100 println(totalCost) }}
The Return Value of the function is an optional type. We can check whether there is a value through the optional binding. Obviously, the stock price is also an optional type, so we continue to useif let
To check whether it has a value.
The above Code has no problems, butif
Nesting is too troublesome. If you have multiple layers of optional types, the following situations may occur:
if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { if let x = xxx() { } } } } } } } } } } } }
Er, the above Code is self-written, but not in the original text.
Besidesif let
You can use optional links to simplify the code. We can use question marks to concatenate multiple optional types:
if let sharePrice = findStockCode(Apple)?.price { let totalCost = sharePrice * 100 println(totalCost)}
The optional chain provides another way to access variables, and the code now looks more clean and tidy. The above is just a basic usage. For more in-depth study, refer to the official documentation.
Interaction between Swift and Objective-C
The available types in Swift are very powerful, although it may take some time to get familiar with them. Optional types make your code clearer and avoid nil problems.
Swift has APIs designed to interact with Objective-C. When we need to interact with APIs of UIKit or other frameworks, you will certainly encounter optional types. The following lists some optional types that may be encountered in UITableView:
func numberOfSectionsInTableView(tableView: UITableView?) -> Int { // Return the number of sections. return 1}func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { // Return the number of rows in the section. return recipes.count}func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! { let cell = tableView.dequeueReusableCellWithIdentifier(Cell, forIndexPath: indexPath) as UITableViewCell cell.textLabel.text = recipes[indexPath.row] return cell}
Summary
For a developer, it is necessary to understand the working principle of the optional type. This is why we write an article specifically to introduce the optional types. It helps developers discover hidden problems during the compilation phase to avoid runtime errors. When you get used to this syntax, you will enjoy the charm of the optional type.
Enjoy the wonderful world. Awesome. (That's right.)