构造过程 (Initialization)
1.存储类型的初始赋值
类和结构在创建实例的时候,必须为所有的存储属性设置值,不能为nil1.1构造器
构造器在创建某个特定类型的新实例的时候调用,最简形式类似不带参数的方法,以init命名struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
println("The default temperature is \(f.temperature)° Fahrenheit")
// prints "The default temperature is 32.0° Fahrenheit"
1.2默认属性值
在属性生命的时候直接为其设置默认值struct Fahrenheit {
var temperature = 32.0
}
2.定制化构造过程
2.1构造参数
在定义构造器的时候提供构造参数,语法跟函数和方法相同struct Celsius {
var temperatureInCelsius: Double = 0.0
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0
2.2内部和外部参数名
构造函数存在一个构造器内部使用的参数名和一个在调用时使用的外部参数名,如果没有提供参数的外部名字,Swift会自动为每个构造器的参数生成一个跟内部参数名相同的外部参数名struct Color {
let red = 0.0, green = 0.0, blue = 0.0
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
// 如果不通过外部参数名传值,编译时无法通过
let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - external names are required
2.3可选属性类型
如果定义的类型包含一个可以为空的存储型属性,需要将其定义为可选类型 (optional type), 则自动初始化为nil,表示这个属性是故意初始化设置为空的class SurveyQuestion {
var text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
println(text)
}
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."
2.4构造过程中常量的修改
只要在构造过程结束后能确定常量的值,就可以在构造过程之中随意修改常量的值// 尽管text属性是常量,但在构造过程之中还是可以修改的,构造过程结束时候不能再修改了
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
println(text)
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
3.默认构造器
Swift为素有属性已提供默认值的但自身没有构造器的结构体或基类提供一个默认的构造器,构造器创建一个将所有属性值都设置为默认值的实例class ShoppingListItem {
var name: String?
var quantity = 1
var purchased = false
}
var item = ShoppingListItem()
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
4.值类型的构造器代理
构造器通过调用其他构造器来完成实例的部分构造,提高代码利用率,称为构造器的代理struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let basicRect = Rect()
// basicRect's origin is (0.0, 0.0) and its size is (0.0, 0.0)
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// originRect's origin is (2.0, 2.0) and its size is (5.0, 5.0)
5.类的继承和构造过程
类里所有的存储类型属性包括继承父类的属性都需要在构造过程中设置初始值,Swift提供两种类型的类构造器来确保所有类实例中的存储属性都能获得初始值5.1指定构造器和便利构造器
指定构造器是类中最主要的构造器,将初始化类中所提供的所有属性,每个类至少需要一个指定构造器,便利构造器是辅助型的构造器,可调用同一类中的指定构造器,并为其参数提供默认值5.2构造器链
Swift采用三条规则来限制构造器之间的代理调用a.指定构造器必须调用其直接父类的指定构造器
b.便利构造器必须调用同一类中定义的其他构造器
c.便利构造器最终必须调用一个指定构造器结束
(指定构造器总是向上代理,便利构造器总是横向代理)
5.3构造器的继承和重载
Swift中的子类默认不会继承父类的构造器,防止父类的简单构造被子类继承,并错误的创建子类的实例,如果希望子类能继承父类相同的构造器,需要定制子类的构造器5.4指定构造器和便利构造器的语法
init(parameters) {
statements
}
// 便利构造器前置 convenience关键字
convenience init(parameters) {
statements
}
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
let namedMeat = Food(name: "Bacon")
// namedMeat's name is "Bacon"
let mysteryMeat = Food()
// mysteryMeat's name is "[Unnamed]"
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
let oneMysteryItem = RecipeIngredient()
let oneBacon = RecipeIngredient(name: "Bacon")
let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name.lowercaseString)"
output += purchased ? " ✔" : " ✘"
return output
}
}
var breakfastList = [
ShoppingListItem(),
ShoppingListItem(name: "Bacon"),
ShoppingListItem(name: "Eggs", quantity: 6),
]
breakfastList[0].name = "Orange juice"
breakfastList[0].purchased = true
for item in breakfastList {
println(item.description)
}
// 1 x orange juice ✔
// 1 x bacon ✘
// 6 x eggs ✘
6.通过闭包和函数来设置属性的默认值
属性可以使用闭包或全局函数来提供默认值,当创建新实例时,对应的闭包或函数就会被调用,返回值当做这个属性的默认值//闭包结尾的大括号后接空得小括号,告诉Swift立刻执行此闭包,如果忽略这个括号,相当于闭包本身作为值赋给属性,而不是将闭包的返回值赋给属性
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}
struct Checkerboard {
let boardColors: Bool[] = {
var temporaryBoard = Bool[]()
var isBlack = false
for i in 1...10 {
for j in 1...10 {
temporaryBoard.append(isBlack)
isBlack = !isBlack
}
isBlack = !isBlack
}
return temporaryBoard
}()
func squareIsBlackAtRow(row: Int, column: Int) -> Bool {
return boardColors[(row * 10) + column]
}
}
let board = Checkerboard()
println(board.squareIsBlackAtRow(0, column: 1))
// prints "true"
println(board.squareIsBlackAtRow(9, column: 9))
// prints "false"
析构过程 (Deinitialization)
类的实例被释放之前,析构函数被立即调用,deinit表示析构过程1.原理
Swift会自动释放不需要的实例以释放资源,但当使用自己的资源的时候,需要清理额外的信息,如创建一个自定义的类来打开文件并写入数据,可能需要在类实例被释放之前关闭该文件每个类组多只有一个析构函数,不允许主动调用,在实例被释放的前一步被自动调用,因为析构函数知道实例被释放才会被调用,所以可以访问实例的所有属性,并进行操作
deinit {
// perform the deinitialization
}
2.操作
struct Bank {
static var coinsInBank = 10_000
static func vendCoins(var numberOfCoinsToVend: Int) -> Int {
numberOfCoinsToVend = min(numberOfCoinsToVend, coinsInBank)
coinsInBank -= numberOfCoinsToVend
return numberOfCoinsToVend
}
static func receiveCoins(coins: Int) {
coinsInBank += coins
}
}
class Player {
var coinsInPurse: Int
init(coins: Int) {
coinsInPurse = Bank.vendCoins(coins)
}
func winCoins(coins: Int) {
coinsInPurse += Bank.vendCoins(coins)
}
deinit {
Bank.receiveCoins(coinsInPurse)
}
}
var playerOne: Player? = Player(coins: 100)
println("A new player has joined the game with \(playerOne!.coinsInPurse) coins")
// prints "A new player has joined the game with 100 coins"
println("There are now \(Bank.coinsInBank) coins left in the bank")
// prints "There are now 9900 coins left in the bank"
playerOne!.winCoins(2_000)
println("PlayerOne won 2000 coins & now has \(playerOne!.coinsInPurse) coins")
// prints "PlayerOne won 2000 coins & now has 2100 coins"
println("The bank now only has \(Bank.coinsInBank) coins left")
// prints "The bank now only has 7900 coins left"
playerOne = nil
println("PlayerOne has left the game")
// prints "PlayerOne has left the game"
println("The bank now has \(Bank.coinsInBank) coins")
// prints "The bank now has 10000 coins"