A first look at Swift 2.0: Notable new features

A first look at Swift 2.0: Notable new features

In the blink of an eye, Swift is already over a year old. This fresh, stylish, type-safe, and faster-executing language has gradually gained popularity among developers. I also love this new programming language very much.

In June this year, the annual WWDC conference came as scheduled. At the conference, Apple released Swift 2.0, which introduced many new features to help developers build applications faster and easier. Here I will also talk about the new features in Swift 2.0 that are worth your attention.

guard Statement

The guard statement is similar to the if statement in that it determines what to execute next based on the Boolean value of the expression after the keyword. However, unlike the if statement, the guard statement only has one code block, unlike the if statement which can have multiple code blocks such as if else.

So what is the role of the guard statement? As the name suggests, it is a guard. The guard statement will execute the code in the following code block only when the Boolean value of the expression after it is false. If it is true, the entire guard statement will be skipped. Let's take an example to see.

Let's take this year's college entrance examination as an example. When entering the examination room, the ID card and admission ticket are generally checked. We write a method like this:

  1. func checkup(person: [String: String!]) {
  2.  
  3. // Check your ID card. If you don't have your ID card, you will not be allowed to enter the examination room.  
  4. guard let id = person[ "id" ] else {
  5. print( "You cannot enter the examination room without an ID card!" )
  6. return  
  7. }
  8.  
  9. // Check the admission ticket. If you don't bring the admission ticket, you will not be allowed to enter the examination room.  
  10. guard let examNumber = person[ "examNumber" ] else {
  11. print( "You cannot enter the examination room without an admission ticket!" )
  12. return  
  13. }
  14.  
  15. // You can enter the examination room only if you have both your ID card and admission ticket  
  16. print( "Your ID number is: \(id), and your admission ticket number is: \(examNumber). Please enter the examination room!" )
  17.  
  18. }
  19. checkup([ "id" : "123456" ]) // You cannot enter the examination room without an admission ticket!  
  20. checkup([ "examNumber" : "654321" ]) // You cannot enter the examination room without an ID card!  
  21. checkup([ "id" : "123456" , "examNumber" : "654321" ]) // Your ID number is: 123456, and your admission ticket number is: 654321. Please enter the examination room!  

The first guard statement in the above code is used to check the ID card. If the ID card is not brought, that is, the expression is false, the code in the curly brackets is executed and returned. The second guard statement checks the admission ticket.

If both certificates are complete, the last print statement is executed, and the codes in the curly braces of the two guard statements above will not be executed because the Boolean values ​​of their expressions are both true.

It is worth noting here that id and examNumber can be used outside the guard statement, that is, after guard verifies its expression, id and examNumber can be used in the scope of the entire method and are unpacked.

Let's write a similar method using an if else statement:

  1. func checkupUseIf(person: [String: String!]) {
  2.  
  3. if let id = person[ "id" ], let examNumber = person[ "examNumber" ] {
  4. print( "Your ID number is: \(id), and your admission ticket number is: \(examNumber). Please enter the examination room!" )
  5. } else {
  6. print( "You cannot enter the examination room if your documents are incomplete!" )
  7. }
  8.  
  9. print( "Your ID number is: \(id), and your admission ticket number is: \(examNumber)" ) // Report an exception  
  10.  
  11. }
  12. checkupUseIf([ "id" : "123456" ]) // Incomplete documents, cannot enter the examination room!  
  13. checkupUseIf([ "examNumber" : "654321" ]) // Incomplete documents, cannot enter the examination room!  
  14. checkupUseIf([ "id" : "123456" , "examNumber" : "654321" ]) // Your ID number is: 123456, and your admission ticket number is: 654321. Please enter the examination room!  

We can see that the method implemented by if else is obviously not as accurate as that implemented by guard. Moreover, the scope of id and examNumber is limited to the first curly brace of if. If it exceeds this scope, the compilation will report an error.

It is not difficult to see from the above two small examples that the guard statement is like a competent guard, which checks layer by layer to prevent anything that is not allowed to happen, and makes the code more readable, which is great.

Exception handling

In the Swift 1.0 era, there was no exception handling and throwing mechanism. If you wanted to handle exceptions, you either used if else statements or switch statements to judge and handle them, or used closure callback functions to handle them, or used NSError to handle them. None of the above methods can handle exceptions as smoothly and leisurely as the try catch exception control statement in Java, and they will also reduce the readability of the code. When Swift 2.0 came, everything was different.

In Swift 2.0, Apple provides an exception control mechanism consisting of five keywords: throws, throw, try, do, and catch. Let's take an example to see how to use it. I'll use the example of using a mobile phone to browse Moments.

First we need to define the exception enumeration. In Swift 2.0, Apple provides the ErrorType protocol that our custom exception enumeration needs to follow:

  1. enum WechatError: ErrorType {
  2. case NoBattery // The phone is out of battery  
  3. case NoNetwork // No network on mobile phone  
  4. case NoDataStream // The phone has no data flow  
  5. }

We define the error enumeration 'wechatError' that causes WeChat to fail to be swiped. Then define a method checkIsWechatOk() to check whether WeChat can be swiped:

  1. func checkIsWechatOk(isPhoneHasBattery: Bool, isPhoneHasNetwork: Bool, dataStream: Int) throws {
  2.  
  3. guard isPhoneHasBattery else {
  4. throw WechatError.NoBattery
  5. }
  6.  
  7. guard isPhoneHasNetwork else {
  8. throw WechatError.NoNetwork
  9. }
  10.  
  11. guard dataStream > 50   else {
  12. throw WechatError.NoDataStream
  13. }
  14.  
  15. }

Note that there is a throws keyword after the method name, which means that the exception generated by this method is thrown to the upper layer. Use the guard statement in the method body to judge various states, and then use the throw keyword to throw the corresponding exception. Then we define the method of swiping WeChat:

  1. func playWechat(isPhoneHasBattery: Bool, isPhoneHasNetwork: Bool, dataStream: Int) {
  2.  
  3. do {
  4. try checkIsWechatOk(isPhoneHasBattery, isPhoneHasNetwork: isPhoneHasNetwork, dataStream: dataStream)
  5. print( "Just brush until the sky darkens!" )
  6. } catch WechatError.NoBattery {
  7. print( "My phone is out of battery, what the hell is going on!" )
  8. } catch WechatError.NoNetwork {
  9. print( "There is no network, let's play stand-alone!" )
  10. } catch WechatError.NoDataStream {
  11. print( "No more data, let's go get some Wifi!" )
  12. } catch {
  13. print( "What the hell!" )
  14. }
  15.  
  16. }
  17. playWechat( true , isPhoneHasNetwork: true , dataStream: 60 ) // Feel free to scroll until you feel dizzy!  
  18. playWechat( true , isPhoneHasNetwork: false , dataStream: 60 ) // There is no network, let's play stand-alone!  
  19. playWechat( false , isPhoneHasNetwork: true , dataStream: 60 ) // My phone is out of battery, how can I play it?  
  20. playWechat( true , isPhoneHasNetwork: true , dataStream: 30 ) // No data flow, go use Wifi!  

In the above code example, the try keyword is used before the method that checks whether WeChat can be swiped, indicating that the method is allowed to throw exceptions. Then the do catch control statement is used to capture the thrown exception and perform related logical processing.

This exception handling mechanism makes Swift more comprehensive and safer, and improves the readability of the code, which is great.

Protocol Extensions

In the Swift 1.0 era, a protocol is basically like an interface, defining several properties and methods for classes, structures, and enumerations to follow and implement. In Swift 2.0, you can extend the properties or methods of a protocol, similar to extending classes and structures. This opens the chapter of protocol-oriented programming.

In Swift, most basic objects follow the CustomStringConvertible protocol, such as Array and Dictionary (Printable protocol in Swift 1.0). This protocol defines a description method for printing objects using the print method. Now we extend this protocol with a method to print the content in uppercase:

  1. var arr = [ "hello" , "world" ]
  2. print(arr.description) // "[hello, world]"  
  3. extension CustomStringConvertible {
  4. var upperDescription: String {
  5. return   "\(self.description.uppercaseString)"  
  6. }
  7. }


print(arr.upperDescription) // "[HELLO, WORLD]"

If we want to achieve the effect of the above example in the Swift 1.0 era, we need to extend Array and Dictionary respectively. Therefore, the extension of the protocol greatly improves our programming efficiency and also makes the code more concise and easy to read.

Changes to print statements

In Swift 1, there are two methods for printing statements in the console, 'println()' and 'print()'. The former prints on a new line, while the latter prints on a continuous line. In Swift 2, 'println()' has become a thing of the past, and has been replaced by a combination of the two. If you want to print on a new line, you now need to write:

  1. print( "I want a new line!" , appendNewline: true )

Available Check

As an iOS developer, everyone wants to use the latest version of iOS API for development, which saves time and effort. However, this is often not the case, because we often need to adapt to older versions of iOS, which will face a problem. Some new features or classes cannot be used in older versions of iOS, so during the coding process, we often judge the iOS version, like this:

  1. if NSClassFromString( "NSURLQueryItem" ) != nil {
  2. // iOS 8 or later  
  3. } else {
  4. // Versions before iOS8  
  5. }

The above is just one way. Before Swift 2.0, there was no standard mode or mechanism to help developers determine the iOS version, and it was easy to make mistakes. After the arrival of Swift 2.0, we have a standard way to do this:

  1. if #available(iOS 8 , *) {
  2. // iOS 8 or later  
  3. let queryItem = NSURLQueryItem()
  4.  
  5. } else {
  6. // Versions before iOS8  
  7.  
  8. }

This feature makes us so happy.

do-while statement rename

The classic do-while statement has been renamed to repeat-while:

  1. var i = 0  
  2. repeat {
  3. i++
  4. print(i)
  5. } while i < 10  

I personally feel it is more intuitive.

The defer keyword

In some languages, there are control statements like try/finally, such as Java. This statement allows us to execute the code that must be executed in the finally code block, no matter what happened before. In Swift 2.0, Apple provides the defer keyword, which allows us to achieve the same effect.

  1. func checkSomething() {
  2.  
  3. print( "CheckPoint 1" )
  4. doSomething()
  5. print( "CheckPoint 4" )
  6.  
  7. }
  8. func doSomething() {
  9.  
  10. print( "CheckPoint 2" )
  11. defer {
  12. print( "Clean up here" )
  13. }
  14. print( "CheckPoint 3" )
  15.  
  16. }
  17. checkSomething() // CheckPoint 1, CheckPoint 2, CheckPoint 3, Clean up here, CheckPoint 4  

In the above example, we can see that after printing "CheckPoint 2", "Clean up here" is not printed, but "CheckPoint 3". This is the role of defer, which delays print("Clean up here"). Let's look at another I/O example:

  1. // pseudocode  
  2. func writeSomething() {
  3.  
  4. let file = OpenFile()
  5.  
  6. let ioStatus = fetchIOStatus()
  7. guard ioStatus != "error"   else {
  8. return  
  9. }
  10. file.write()
  11.  
  12. closeFile(file)
  13.  
  14. }

The above example is a pseudo code of an I/O operation. If the ioStatus obtained is normal, then there is no problem with the method. If the ioStatus obtained is an error, it will be caught by the guard statement and the return operation will be executed. In this case, closeFile(file) will never be executed, and a serious bug will be generated. Let's see how to use defer to solve this problem:

  1. // pseudocode  
  2. func writeSomething() {
  3.  
  4. let file = OpenFile()
  5. defer {
  6. closeFile(file)
  7. }
  8.  
  9. let ioStatus = fetchIOStatus()
  10. guard ioStatus != "error"   else {
  11. return  
  12. }
  13. file.write()
  14.  
  15. }

We put closeFile(file) in the defer code block, so that even if ioStatus is error, the code in defer will be executed before return is executed, which ensures that no matter what happens, the file will be closed in the end.

Defer is another feature that ensures the robustness of our code, and I like it very much.

Of course, there are more new features in Swift 2.0 than those listed above, but a glimpse of the whole picture shows that Swift 2.0 strives to be faster and safer to the extreme, which is good news for developers. Let us enjoy this wonderful language to the fullest.

<<:  Hprose for Node.js 1.6.0 released

>>:  Example analysis: Performance optimization of "Qichu Encyclopedia"

Recommend

Direct-operated e-commerce information flow advertising strategy

When the Internet becomes a traditional industry,...

Even though Apple is hiring News editors, algorithms still decide what you read

[[137024]] When you are used to deciding what you...

How to do marketing if the budget is not enough?

We all know that how many people can be promoted ...

Build a user operation system in 5 steps!

User operation is an invisible skill that many ne...

What is LSD? It once made Steve Jobs addicted

Lysergic acid diethylamide, also known as "l...

Zhihu's latest recommendation algorithm

Why do some people’s answers on Zhihu always have...

How to make your copywriting as popular as Jay Chou’s lyrics?

The reason why Jay Chou's songs are timeless ...