注:本文为自己学习The Swift Programming Language的学习笔记
1.对象和类
1.1简单类定义和对象实例化及使用
类定义关键词为class,存储属性的声明如同常量或变量声明,方法的声明如同函数声明。
构造函数关键词init,class的每一个存储属性必须要么在声明时赋值,要么在构造函数中给出赋值。
class Person {
var name : String
init (name : String){
self.name = name
}
func sayHello() {
println("Hello,I am \(name)")
}
}
var person = Person(name : "JCGuo")
person.sayHello()
构造函数中self.name区别于参数name,和Java用法相同。
deinit关键词来声明析构函数,在对象被回收之前可以完成必要的清理工作。
1.2继承和覆写
: 冒号关键词用于继承声明,继承语法中Swift支持多态中的覆写override,声明覆写一定要使用关键词override。
class Student : Person{
override func sayHello() {
println("Hello,I am a student named \(name)")
}
}
person = Student(name : "JCGuo")
person.sayHello()
1.3计算属性
计算属性区别于普通存储属性,可以有getter取值器和setter赋值器。set方法的默认传入值为newValue,也可以在set后加括号给出传入值变量名。
class Square {
var sideLength : Double
init (sideLength : Double) {
self.sideLength = sideLength
}
var perimeter : Double {
get {
return 4 * sideLength
}
set {
sideLength = newValue / 4
}
}
}
var square = Square(sideLength : 3.0)
println("Perimeter of this square is \(square.perimeter).")
计算属性是和某个存储属性相关联的属性,它并不存储属性值,只是提供间接获取、设置存储属性的方法。
比如例子中的正方形边长和周长,后者是前者4倍的线性关系。
计算属性可以是只读的,要么出于对存储属性的保护,要么只能由存储属性推导出计算属性(非双射):
class Person {
var name : String, age : Int
init (name : String, age : Int) {
self.name = name
self.age = age
}
var isAdult : Bool {
return age >= 18
}
func sayHello() {
println("Hello,I am \(name)")
}
}
var person = Person(name : "JCGuo",age : 20)
person.sayHello()
if person.isAdult {
println("Behave yourself as an adult!")
}
是否成年和年龄不能构成双射,由年龄能推出是否成年。只有getter的计算属性可以省略get{ }框体。
1.4willSet和didSet属性观察器
willSet和didSet属性观察器在属性被赋值的之前和之后进行调用,完成一些特定工作。
willSet中statement的值为初始属性值,默认newValue为现在的赋值值。
didSet中statement的值为已经赋值后的属性值,默认oldValue为之前的属性值。
newValue和oldValue可以在willSet和didSet之后显示定义名称。
class WillDillSetExample {
var statement : String = "nil" {
willSet {
println("About to set statement from \(statement) to \(newValue)!")
}
didSet {
println("Setting from \(oldValue) to \(statement) is done!")
}
}
}
var example = WillDillSetExample()
example.statement = "Hello Swift"
example.statement = "Let's Go"
注意,计算属性不能有属性观察器willSet和DidSet,get和set它们两个不能同时出现。
2.枚举和结构体
2.1枚举
枚举声明关键词为enum,枚举名后面接冒号和枚举类型。
枚举集合要用case关键词给出,第一个枚举默认原始值为0。这里初始化Ace原始值为1,后面依次为2、3...,和Java一样。
枚举可以像类一样定义方法,声明和类中声明一样。
enum Rank : Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace: return "ace"
case .Jack: return "jack"
case .Queen:return "queen"
case .King: return "king"
default: return String(self.toRaw())
}
}
}
let ace = Rank.Ace
println("\(ace.simpleDescription()) ranks \(ace.toRaw()) in Cards.")
最后调用了枚举类型的默认方法toRaw,返回一个Int型的值,表示该枚举值在枚举类型中对应的原始值。
此外枚举类型还有fromRaw默认方法,给出原始值返回一个枚举类型的枚举值。
注意由于给出原始值在枚举类型中不一定有枚举值与它对应,用一个if-let语句把相应操作包装起来,否则编译器不通过,因为fromRaw返回的是可空的枚举类型而不是枚举类型。
if let test = Rank.fromRaw(12) {
println("This is a \(test.simpleDescription()).")
}
得到输出为:This is a queen.
Swift枚举在不存在有意义的原始值(比如原始值类型为String或直接省略掉时),可以直接忽略原始值。
2.2结构体
使用struct关键字声明结构体,结构体在很多方面和类相似,比如声明它的语法,比如它也可以有属性、构造函数、方法等。
但是结构体除了不能像类一样继承、类型转换等,与类最重要的一个区别是:类的实例是按引用传递而结构体的实例是按值传递的。
下面给出一个例子来区别结构体和类的两种传递方式:
struct Resolution {
var width = 0
var height = 0
func format() -> String {
return "\(self.width)*\(self.height)"
}
}
class Video {
var resolution : Resolution
var name : String
init(resolution : Resolution, name :String) {
self.resolution = resolution
self.name = name
}
}
var hd = Resolution(width : 1920, height : 1080)
var cinema = hd
cinema.width = 2048
println("HD is \(hd.format()),but CINEMA is \(cinema.format())")
var video1 = Video(resolution : hd, name : "Game of Thrones")
var video2 = video1
video2.resolution = cinema
println("Dude, have you got the latest \(video1.resolution.format()) of \(video1.name)?")
println("Of course I got the latest \(video2.resolution.format()) one.")
定义了一个分辨率结构体,和一个视频类。
实例化HD分辨率,把HD分辨率赋值给新的变量Cinema,修改Cinema分辨率的宽度而高度保持不变。(注:有的参考博客说定义常量结构体而它的属性可以改变因为不是整个结构体的改变,但是我实验的时候XCode是会报错的,即常量结构体的属性也不能更改)
得到的输出是:HD is 1920*1080,but CINEMA is 2048*1080,说明两个结构体实例之间没有联系,在赋值的时候是完全的拷贝hd实例到新实例的。
而Video作为类,它的实例video1和video2在赋值后是指向一个对象的,可以理解为指针。修改video2实例的属性,video1的属性同样更改。
因而得到的输出是:
Dude, have you got the latest 2048*1080 of Game of Thrones?
Of course I got the latest 2048*1080 one.
2.3枚举成员的关联值
枚举支持在枚举成员上关联值,同一个枚举中的不同枚举成员可以有不同关联值。
枚举成员的关联值和他的原始值没有关系:一个枚举成员对于所有枚举类型实例有唯一原始值,在声明中定义;但关联值可以不同,它是在实例化的时候提供的。
enum ServerResponse {
case Result(String, String)
case Error(String)
}
let success = ServerResponse.Result("6:00 am", "8:09 pm")
let failure = ServerResponse.Error("Out of cheese.")
var serverResponse : String
switch success {
case let .Result(sunrise, sunset):
serverResponse = "Sunrise is at \(sunrise) and sunset is at \(sunset)."
case let .Error(error):
serverResponse = "Failure... \(error)"
}
println(serverResponse)