Swift类型转换
关于「类型转换」(Type Casting),《The Swift Programming Language》描述如下:
Type casting is a way to check the type of an instance, and/or to treat that instance as if it is a different superclass or subclass from somewhere else in its own class hierarchy.
在Swift中,有两个关键字与类型转换相关:is和as。前者体现的是Swift的内省机制(introspection),用于检查某个实例的类型(类似于OC中的isKindOfClass:和isMemberOfClass:);后者用于类型转换,即将某个类型实例转换为其父类的实例或者子类的实例。
Swift中的类型转换是一个非常容易理解的概念,本文将以代码为辅助对之进行简单阐述。
首先定义几个类为后文服务:
// 「媒体」类
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")
]
很容易理解,该library的类型是[MediaItem]。站在物理的角度,library中存储的元素要么是Movie类型实例,要么是Song类型实例。但站在逻辑的角度,你若遍历library,则取出的实例会是MediaItem类型的,而不是Movie或者Song。所以,若想让library中的元素基于它们本来的类型处理事情,那么需要检查它们的类型或者向下转换它们的类型到其他类型。
Checking Type
用类型检查操作符is来检查一个实例是否属于特定类型。若实例属于那个类型,类型检查操作符返回true,否则返回false。
如下定义了两个变量,movieCount和songCount,分别用来计算library中Movie和Song类型实例的数量,如下:
var movieCount =
var songCount = for item in library {
if item is Movie {
movieCount++
} else if item is Song {
songCount++
}
} println("Media library contains \(movieCount) movies and \(songCount) songs")
// prints "Media library contains 2 movies and 3 songs"
Downcasting
「Downcasting」常常被翻译为「向下转型」。某个常量或变量在逻辑层面可能属于某种类型,但在物理层面可能属于其某个子类类型。上述library中的元素就是这种情况(逻辑层面包含的元素都属于MediaItem类型,但是实际上有的属于Movie类型,有的属于Song类型)。对于这种情况,你可以使用转换操作符as向下转型(譬如MediaItem转Song或Movie)。
在OC中,类型转换非常简单,譬如:
UIViewController *VC = [[UIViewController alloc] init];
UITableViewController *tableVC = (UITableViewController *)VC;
tableVC.tableView.background = [UIColor whiteColor];
这段代码当然会通过编译,但是会产生runtime错误,至于原因就不啰嗦了。
对于Swift也一样,downcasting也可能会失败。不同的是,在OC中,类型转换成功或失败是无法获知的(因为人家是动态语言嘛,类型检测在runtime才会进行);Swift是强类型语言,类型转换成功与否是可以检查到的,简单来说,Swift的downcasting会返回一个optional,若失败了,则该optional的值为nil;
类型转换操作符有两种不同形式:
as?,返回一个optional,若转换成功,则包含你期待的类型实例,若失败,则是nil;as!,相当于转换后强制解包,若转换失败,则会造成runtime错误;
显然,当你不确定是否能转换是否成功时,使用as?;否则,使用as!。
P.S:能不能直接使用as?No!
下面的示例遍历了上文的library常量,并打印出其中所有元素的描述信息(名字,音乐作者或者电影导演),如下:
for item in library {
if let movie = item as? Movie {
println("Movie: '\(movie.name)', dir. \(movie.director)")
} else if let song = item as? Song {
println("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
*/
Any and AnyObject
虽然Swift是强类型语言,但是OC不是啊,譬如OC中数组可以存放允许类型的类对象(不要求类型一致);考虑到兼容性,Swift为不确定类型提供了两种特殊类型:
AnyObject可以代表任何类类型的实例;Any可以表示任何类型实例,包括方法/函数类型;
值得一提的是,AnyObject和Any尽可能少用,毕竟类型越清晰越好,Swift文档是这么描述的:
Use
AnyandAnyObjectonly when you explicitly need the behavior and capabilities they provide. It is always better to be specific about the types you expect to work with in your code.
AnyObject
使用Cocoa APIs时,常常会接收到一个[AnyObject]类型的数组,或者说「一个任何对象类型的数组」。这是因为OC没有明确的类型化数组。然而,很多时候我们常常可以确定知道包含在数组(获取其他集合)中元素的确切类型;在这种情况下,可以使用as!来向下对元素类型进行转换(转到比AnyObject更确切的类型)。如下是对AnyObject向下转型的一个栗子:
let someObjects: [AnyObject] = [
Movie(name: "2001: A Space Odyssey", director: "Stanley Kubrick"),
Movie(name: "Moon", director: "Duncan Jones"),
Movie(name: "Alien", director: "Ridley Scott")
]
因为知道这个数组只包含Movie实例,你可以直接用as!向下转型并解包到Movie类型:
for object in someObjects {
let movie = object as! Movie
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
/*输出:
Movie: '2001: A Space Odyssey', dir. Stanley Kubrick
Movie: 'Moon', dir. Duncan Jones
Movie: 'Alien', dir. Ridley Scott
*/
还有一种更简洁的写法:
for movie in someObjects as! [Movie] {
println("Movie: '\(movie.name)', dir. \(movie.director)")
}
Any
Any和AnyObject差不多,只是后者仅限于类类型,前者通吃所有类型。比较简单,这里不赘述了。
Swift类型转换的更多相关文章
- Swift - 类型转换(as as! as?)
swift 类型转换 一,as 1,as使用场合 (1)从派生类转换为基类,向上转型(upcasts) class Animal {} class Cat: Animal {} let cat = C ...
- swift:类型转换(is用作判断检测、as用作类型向下转换)
类型转换是一种检查类实例的方式,并且哦或者也是让实例作为它的父类或者子类的一种方式. 类型转换在Swift中使用is 和 as操作符实现.这两个操作符提供了一种简单达意的方式去检查值的类型或者转换 ...
- Swift类型转换 和 类型别名的定义(typealias)
(一)类型转换 类型转化在 Swift 中是比较严格的,不同类型之间可以认为是不能相互转化的,只能重新产生一个对象和值,并拷贝一份. 1.0 整型数值之间的转换. // 不同类型是不能直接相加的,这时 ...
- Swift 类型转换
1.类型转换 1.1 隐式类型转换 如 C 语言的类型转换 1.2 显式类型转换 Swift 语言是一种强类型语言,其整型的强制类型转换就是调用了参数类型对应的整形扩展构造方法,然后通过对应扩展构造方 ...
- swift类型转换之Could not cast value of type xxx to xxx错误的一种特殊情况记录
之前swift项目打包成Framework静态库,提供给OC项目套入使用时,有时会抱这样一个错误: 这个错误发生的概率比较随机,有时会,有时不会,而且这句话在swift中的使用,是做model类型强制 ...
- OC与Swift的区别二(常量、变量、运算符)
4.常量与变量声明 oc的变量声明使用 类型 变量名 = 变量值的方式,其中类型为系统内置数据类型或自定义类型,变量名需由英文字母开头且不能包含特殊字符 swift变量声明使用 var 变量名 = ...
- 【译】Swift 字符串速查表
[译]Swift 字符串速查表 2015-12-18 10:32 编辑: suiling 分类:Swift 来源:CocoaChina翻译活动 10 5585 Swift字符串 招聘信息: iOS高级 ...
- iOS核心动画高级技巧之图层变换和专用图层(二)
iOS核心动画高级技巧之CALayer(一) iOS核心动画高级技巧之图层变换和专用图层(二)iOS核心动画高级技巧之核心动画(三)iOS核心动画高级技巧之性能(四)iOS核心动画高级技巧之动画总结( ...
- swift中文文档- 类型转换
未翻译完 待续(英语烂,求斧正) Type Casting 类型转换 Type casting is a way to check the type of an instance, and/or to ...
随机推荐
- 我是如何通过CSRF拿到Shell的
织梦内容管理系统(DedeCms) 以简单.实用.开源而闻名,是国内最知名的PHP开源网站管理系统,也是使用用户最多的PHP类CMS系统,在经历多年的发展,目前的版本无论在功能,还是在易用性方面,都有 ...
- SVN服务器配置说明 【转】
http://www.cnblogs.com/ricksun/articles/1564905.html 1.前 言 花了72小时,终于把 Subversion 初步掌握了.从一个连“什么是版本控制” ...
- php自己编译安装后,再给这个编译安装的php版本添加拓展模块的处理办法。
原文: https://www.cnblogs.com/zongyl/p/5924627.html 说明,给编译安装之后的php 添加pgsql 拓展成功. --------------------- ...
- 【IE】IE对line-height 失效的的解决方案
微软的IE9 + Extjs3.1 确实头疼.在使用了line-height:20px 的Tree的样式,可是一直没有生效, 以下给出3中解决方式: 方案1.加padding-top: <div ...
- sass的使用(载)
一.什么是SASSSASS是一种CSS的开发工具,提供了许多便利的写法,大大节省了设计者的时间,使得CSS的开发,变得简单和可维护.本文总结了SASS的主要用法.我的目标是,有了这篇文章,日常的一般使 ...
- Nginx简单了解
1.静态HTTP服务器 首先,Nginx是一个HTTP服务器,可以将服务器上的静态文件(如HTML.图片)通过HTTP协议展现给客户端. 配置: server { listen80; # 端口号 lo ...
- 二进制安装Mysql 5.6(免编译)
安装系统基础软包 yum install -y make bc perl gcc openssl openssl-devel ncurses ncurses-devel 安装方式:二进制免编译安装 查 ...
- 将txt文件数据存入excel表格
前言 最近使用Appium自动化在测试设备配网的情况,需要记录每次成功与否和耗时时间. 由于App不是很稳定,执行一段时间会奔溃,因此数据只能通过追加的形式写入到txt文件. 实现过程 存储在txt文 ...
- activity fragment 转场动画
http://www.cnblogs.com/avenwu/p/3372736.html v4 fragment fragmentTransaction.setCustomAnimations(R.a ...
- (转) 实现wince datagrid 上下滑屏数据浏览
开发 基于wince 手持设备数据库应用时 由于是触摸屏 当datagrid 数据过多 往往用户烦于去控制又窄又细的上下滚动条 尤其是高分辨率的屏上 (如魅族M8系统 720×480) 而且datag ...