您的当前位置:首页Swift Type Casting

Swift Type Casting

2024-12-13 来源:哗拓教育

在Swift中,有两种方式实现类型转换:is 和 as

可以在类的层级中检查类实例的类型,或者在同一个类的层级中转换为其他类。

例如,有如下类,及其子类:
<pre><code>
class MediaItem {
var name: String
init(name: String) {
self.name = name
}
}

class Movie: MediaItem {
var director: String
init(name: String, director: String) {
self.director = director
super.init(name: name)
}
}

class Song: MediaItem {
var artist: String
init(name: String, artist: String) {
self.artist = artist
super.init(name: name)
}
}

let library = [
Movie(name: "Casablanca", director: "Michael Curtiz"),
Song(name: "Blue Suede Shoes", artist: "Elvis Presley"),
Movie(name: "Citizen Kane", director: "Orson Welles"),
Song(name: "The One And Only", artist: "Chesney Hawkes"),
Song(name: "Never Gonna Give You Up", artist: "Rick Astley")
]
</code></pre>

数组library,swift推断出共有父类“MediaItem”,所以library是一个[MediaItem]数组。

检查类型 is

<pre><code>
var movieCount = 0
var songCount = 0

for item in library {
if item is Movie {
++movieCount
} else if item is Song {
++songCount
}
}

print("Media library contains (movieCount) movies and (songCount) songs")
// prints "Media library contains 2 movies and 3 songs"
</code></pre>

类型转换(downcasting) as

  • as? 在不确定转换能否成功时使用。不能转换则返回nil
  • as! 在确定转换能成功时使用。如果类型错误,将会产生runtime error

在下例中,无法确定item到底是Movie还是Song,所以适合使用as?
<pre><code>
for item in library {
if let movie = item as? Movie {
print("Movie: '(movie.name)', dir. (movie.director)")
} else if let song = item as? Song {
print("Song: '(song.name)', by (song.artist)")
}
}

// Movie: 'Casablanca', dir. Michael Curtiz
// Song: 'Blue Suede Shoes', by Elvis Presley
// Movie: 'Citizen Kane', dir. Orson Welles
// Song: 'The One And Only', by Chesney Hawkes
// Song: 'Never Gonna Give You Up', by Rick Astley
</code></pre>

Any、AnyObject 类型的转换:

  • AnyObject,可以表示任意类的实例
  • Any,可以表示所有类型的实例,包括function type

AnyObject

使用Cocoa API时,通常返回[AnyObject]数组,这是因为Objective-C的数组没有描述内部对象类型。不过可以在调用的API的说明信息中得到数组内对象的类型。
在这种情况下,就可以使用as!将AnyObject转换为更具体的类型,例如:
<pre><code>
let someObjects: [AnyObject] = [
Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
Movie(name: "Moon", director: "Duncan Jones"),
Movie(name: "Alien", director: "Ridley Scott")
]
</code></pre>

因为知道数组中只有Movie类型的数据,所里可以使用as!直接将AnyObjiect转换为Movie类型
<pre><code>
for object in someObjects {
let movie = object as! Movie
print("Movie: '(movie.name)', dir. (movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones
// Movie: 'Alien', dir. Ridley Scott
</code></pre>

更简洁的代码如下,直接将数组[AnyObject]转换为[Movie]数组
<pre><code>
for movie in someObjects as! [Movie] {
print("Movie: '(movie.name)', dir. (movie.director)")
}
// Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
// Movie: 'Moon', dir. Duncan Jones
// Movie: 'Alien', dir. Ridley Scott
</code></pre>

Any

things.append(0)
things.append(0.0)
things.append(42)
things.append(3.14159)
things.append("hello")
things.append((3.0, 5.0))
things.append(Movie(name: "Ghostbusters", director: "Ivan Reitman"))
things.append({ (name: String) -> String in "Hello, (name)" })
数组内有两个Int,两个Double,一个String,一个(Double,Double)元组,一个Movie,一个闭包String -> String。

通过在switch中使用 is 和 as,可以发现那些Any,AnyObject类型的常量、变量的具体类型。
for thing in things {
switch thing {
case 0 as Int:
print("zero as an Int")
case 0 as Double:
print("zero as a Double")
case let someInt as Int:
print("an integer value of (someInt)")
case let someDouble as Double where someDouble > 0:
print("a positive double value of (someDouble)")
case is Double:
print("some other double value that I don't want to print")
case let someString as String:
print("a string value of "(someString)"")
case let (x, y) as (Double, Double):
print("an (x, y) point at (x), (y)")
case let movie as Movie:
print("a movie called '(movie.name)', dir. (movie.director)")
case let stringConverter as String -> String:
print(stringConverter("Michael"))
default:
print("something else")
}
}

// zero as an Int
// zero as a Double
// an integer value of 42
// a positive double value of 3.14159
// a string value of "hello"
// an (x, y) point at 3.0, 5.0
// a movie called 'Ghostbusters', dir. Ivan Reitman
// Hello, Michael
</code></pre>

显示全文