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

Using Cocoa data types

We have looked at several native Swift data types, such as the string, array, and dictionary types. While using these types is definitely preferred, as part of the Objective-C interoperability, Apple has provide convenient and effective ways to work with Cocoa data types from within our Swift applications.

Some of the Cocoa and Swift data types can be used interchangeably, others are automatically converted between Cocoa and Swift data types. Those data types that can be used interchangeably or converted are called bridged data types.

Swift also provides an overlay for working with foundation data types. This lets us work with foundation data types in a way that feels more like native Swift types. If we need to use these foundation data types, we need to add the following import statement to the top of the Swift file:

import Foundation

Let's take a look at how to work with some common Cocoa data types.

NSNumber

Swift will automatically bridge certain native numeric types, such as Int, UInt, Float, Bool, and Double to an NSNumber object. This allows us to pass these native numeric types to arguments that expect an NSNumber object. This automatic bridging only works one way because an NSNumber object can contain various numeric types; therefore, the Swift compiler will not know which numeric type to convert the NSNumber to. The following examples show how to go from a native Swift Int and Double to an NSNumber, and how to convert it back to the Swift Int and Double. Let's have a look at the following code:

var inum = 7    //Creates an Int
var dnum = 10.6 //Creates a Double

var insnum: NSNumber = inum  //Bridges the Int to a NSNumber
var dnsnum: NSNumber = dnum  //Bridges the Double to a NSNumber

var newint = Int(insnum)       //Creates an Int from a NSNumber
var newdouble = Double(dnsnum) //Creates a Double from a NSNumber

In the preceding code, Swift automatically converts the inum and dnum to NSNumber objects without any typecasting; however, when we try to convert the NSNumber objects back to Int or Double types of Swift, we need to typecast the NSNumber objects to tell Swift what type of numbers we are converting to.

NSString data type

Swift will automatically bridge between the NSString class and the Swift native string type. This allows us to pass the native string type to arguments that expect an NSString object. When we use mix and match to integrate Objective-C APIs with our Swift project, it automatically converts all NSString objects to native Swift string types. When we use mix and match to import Swift APIs with our Objective-C projects, it automatically converts Swift string types to NSString objects.

This automatic bridging allows us to call NSString methods on our Swift strings. Swift automatically converts the string to an NSString object, calls the method, and then converts the returned value back to a Swift string type. The following example shows how to create a path with a Swift string using the stringByAppendingPathComponent() method of NSString:

var str = "http://www.packtpub.com"
var path = str.stringByAppendingPathComponent("swift")
//path contains http://www.packtpub.com/swift

To convert an NSString object to a string type, we will use the as keyword. Since an NSString object can always be converted to a string type, we do not need to use the optional version of this typecasting operator (as?). The following example converts an NSString object to a native Swift string type, and then calls the toInt() method, from the Swift string type, to convert the string to an integer, as shown in the following code:

var nsstr: NSString = "1234"
var num = (nsstr as String).toInt() //num contains the number 1234

In the preceding code, the num variable will contain the number 1234 and not the string 1234.

NSArray

Swift will automatically bridge between the NSArray class and the Swift native array type. Since the elements of an NSArray object are not required to be of the same type, when we bridge from an NSArray object to a Swift array, the elements of the Swift array are set to the [AnyObject] type. The [AnyObject] type is an object that is an instance of an Objective-C or Swift class or can be bridged to one.

The following example shows how we can create an NSArray object in Swift that contains both string and int types, and then creates a Swift array from that NSArray object:

var nsarr: NSArray = ["HI","There", 1,2]
var arr = nsarr as [AnyObject]

In the preceding code, nsarr: NSArray contains four elements: HI, There, 1, and 2. In nsarr NSArray, two of the elements are string types and two are int types. When we convert the nsarr: NSArray to a Swift array, the arr array becomes an array of AnyObject types.

If the NSArray contains a specific object type, once it is bridged to a Swift array, we can downcast the Swift array of [AnyObject] to a Swift array of the specific object types. The only catch to this downcasting is if any element of the array is not of the object type specified, the downcasting will fail and the new array will be set to nil. The following example shows how to downcast an array:

var nsarr: NSArray = ["HI","There"]
var arr = nsarr as [AnyObject]
var newarr = arr as? [String]

In the preceding example, newarr will be an array of strings that contains two elements. Now, let's change the original NSArray to include two integers, as well as the two strings. The new code will now look like this:

var nsarr: NSArray = ["HI","There", 1, 2]
var arr = nsarr as [AnyObject]
var newarr = arr as? [String]

Since the original NSArray defines an array of both strings and integers, when we attempt to downcast the Swift array from an array of [AnyObject] to an array of string, the downcasting fails and the newarr variable is set to nil.

NSDictionary

Just like NSArray, Swift will automatically bridge between NSDictionary objects and the Swift dictionary types. When we bridge from an NSDictionary object to a Swift dictionary, the resulting dictionary will be of type [NSObject: AnyObject]. Also, like the array, we can downcast the dictionary of [NSOdbject:AnyObject] to a dictionary of specified types. The following example shows how to create NSDictionary, bridge the NSDictionary object to a Swift dictionary, and, finally, downcast the Swift dictionary to the [String:String] type:

var nsdic: NSDictionary = ["one":"HI", "two":"There"]
var dic:Dictionary = nsdic
var newdic = dic as? [String:String]

If we attempt to downcast the dictionary to a type that is not valid for either the key or value, the downcasting will fail and the resulting dictionary will be set to nil. The following example illustrates this where the resulting newdic dictionary will be nil because the value associated with the two key is an integer rather than a string.

var nsdic: NSDictionary = ["one":"HI", "two":2]
var dic:Dictionary = nsdic
var newdic = dic as? [String:String]