当前位置: 首页 > 编程学习 > 其它语言 > Swift > 正文

Swift4 初始化,例子代码

2018-04-22 来源:博客园/CC_Joy

初始化

苹果官方文档 Initialization

苹果文档中文翻译 初始化

类、结构体、枚举,准备实例的过程,叫初始化。这个过程需要,初始化器,来保证新的实例在第一次使用时,正确初始化。

为储存属性设置初始化值

创建实例时,必须为储存属性设置一个初始值,或分配一个默认的属性值。

初始化器

创建特定类型的实例时,调用初始化器。使用 init 关键字。

init() {
    // perform some initialization here
}
struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}
var f = Fahrenheit()
print("The default temperature is \(f.temperature)° Fahrenheit")
// prints "The temperature is 32.0° Fahrenheit"

默认的属性值

上边的例子简写为:

struct Fahrenheit {
    var temperature = 32.0
}

自定义初始化

输入形参和可选类型,来自定义初始化过程,或初始化时,分配常量属性。

初始化形式参数

struct Celsius {
    var temperatureInCelsius: Double
    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

形式参数名和实际参数名标签

初始化器的参数名称和类型,区别初始化器时非常重要。没有时,Swift自动提供。

struct Color {
    let red, green, blue: Double
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    init(white: Double) {
        red   = white
        green = white
        blue  = white
    }
}
 
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
let halfGray = Color(white: 0.5)
 
let veryGreen = Color(0.0, 1.0, 0.0)
// this reports a compile-time error - external names are required

初始化器形式参数(无实际参数标签)

不想写实际参数标签,可以用下划线 _ 替代。

struct Celsius {
    var temperatureInCelsius: Double
    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}
 
let bodyTemperature = Celsius(37.0)
// bodyTemperature.temperatureInCelsius is 37.0

可选属性类型

可选类型属性,自动初始化为 nil,表示,初始化时故意设为“还没有值”。

class SurveyQuestion {
    var text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
cheeseQuestion.ask()
// prints "Do you like cheese?"
cheeseQuestion.response = "Yes, I do like cheese."

初始化中分配常量属性

初始化中,给常量属性赋值,保证在初始化结束时,有确定值。

对实例而言,初始化中,只能通过引用的类修改常量属性,不能被子类修改。

class SurveyQuestion {
    let text: String
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"

默认初始化器

没有提供初始化器,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)

值类型的初始化器委托

初始化器调用其他初始化器来执行部分实例的初始化,即初始化器委托

值类型中,写自身自定的初始化器时,用 self.init 从相同值类型里引用其他初始化器。而且只能在初始化器里使用。

把自定义初始化器写在扩展里,让自定义值类型使用默认初始化器初始化、成员初始化器初始化、自定义初始化器初始化。

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)
 
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
    size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

类的继承和初始化

Swift 为类类型定义了两种初始化器以确保所有的存储属性接收一个初始值。

指定初始化器和便捷初始化器

指定初始化器是类的主要初始化器,初始化所有类引用属性和调用父类初始化器。通常一个类只有一个。

便捷初始化器是次要初始化器,为一个类支持初始化器。

指定初始化器和便捷初始化器语法

指定初始化器:

init(parameters) {
    statements
}

便捷初始化器,用 convenience修饰符:

convenience init(parameters) {
    statements
}

类类型的初始化器委托

简单记忆,规则如下:

指定初始化器必须总是向上委托。 便捷初始化器必须总是横向委托。

详细查阅文档。

两段初始化

第一阶段,存储属性引入类,分配初始值,初始状态确定。

第二阶段,在新实例使用之前定制它的存储属性。

具体解释,及安全检查,详见文档

初始化器的继承和重写

子类初始化器匹配父类指定初始化器的时候,可以重写,使用 override 修饰符。匹配父类便捷初始化器的时候,不用写。

class Vehicle {
    var numberOfWheels = 0
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
}
 
let vehicle = Vehicle()
print("Vehicle: \(vehicle。description)")
// Vehicle: 0 wheel(s)
 
class Bicycle: Vehicle {
    override init() {
        super.init()
        numberOfWheels = 2
    }
}
 
let bicycle = Bicycle()
print("Bicycle: \(bicycle.description)")
// Bicycle: 2 wheel(s)

子类不能修改继承过来的常量属性。

自动初始化器的继承

如果子类引入的新属性都有默认值,

规则一,子类没有定义任何指定初始化器,自动继承父类所有指定初始化器。 规则二,子类提供了所有父类指定初始化器的实现。自动继承父类所有便捷初始化器。

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)
    }
    override 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)"
        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 {
    print(item.description)
}
// 1 x Orange juice ✔
// 1 x Bacon ✘
// 6 x Eggs ✘

可失败的初始化器

定义一个可失败的初始化器,在 init 关键字后添加问号 ?

struct Animal {
    let species: String
    init?(species: String) {
        if species.isEmpty { return nil }
        self.species = species
    }
}
 
let someCreature = Animal(species: "Giraffe")
// someCreature is of type Animal?, not Animal
 
if let giraffe = someCreature {
    print("An animal was initialized with a species of \(giraffe.species)")
}
 
// prints "An animal was initialized with a species of Giraffe"
 
let anonymousCreature = Animal(species: "")
// anonymousCreature is of type Animal?, not Animal
 
if anonymousCreature == nil {
    print("The anonymous creature could not be initialized")
}
// prints "The anonymous creature could not be initialized"

枚举的可失败的初始化器

enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}
 
let fahrenheitUnit = TemperatureUnit(symbol: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// prints "This is a defined temperature unit, so initialization succeeded."
 
let unknownUnit = TemperatureUnit(symbol: "X")
if unknownUnit == nil {
    print("This is not a defined temperature unit, so initialization failed.")
}
// prints "This is not a defined temperature unit, so initialization failed."

带有原始值的枚举的可失败初始化器

带有原始值的枚举会自动获得一个可失败初始化器

enum TemperatureUnit: Character {
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}
 
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
if fahrenheitUnit != nil {
    print("This is a defined temperature unit, so initialization succeeded.")
}
// prints "This is a defined temperature unit, so initialization succeeded."
 
let unknownUnit = TemperatureUnit(rawValue: "X")
if unknownUnit == nil {
    print("This is not a defined temperature unit, so initialization failed.")
}
// prints "This is not a defined temperature unit, so initialization failed."

初始化失败的传递

横向委托到同一个类,结构体或枚举里的另一个可失败初始化器。

class Product {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}
 
class CartItem: Product {
    let quantity: Int
    init?(name: String, quantity: Int) {
        if quantity < 1 { return nil }
        self.quantity = quantity
        super.init(name: name)
    }
}
 
if let twoSocks = CartItem(name: "sock", quantity: 2) {
    print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
}
// prints "Item: sock, quantity: 2"
 
if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
    print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
} else {
    print("Unable to initialize zero shirts")
}
// prints "Unable to initialize zero shirts"

重写可失败初始化器

用子类的非可失败初始化器重写父类可失败初始化器,向上委托到父类初始化器的唯一办法是,强制展开父类可失败初始化器的结果。

class Document {
    var name: String?
    // this initializer creates a document with a nil name value
    init() {}
    // this initializer creates a document with a non-empty name value
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}
 
class AutomaticallyNamedDocument: Document {
    override init() {
        super.init()
        self.name = "[Untitled]"
    }
    override init(name: String) {
        super.init()
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}
 
class UntitledDocument: Document {
    override init() {
        super.init(name: "[Untitled]")!
    }
}

可失败初始化器 init!

可以使用可失败初始化器创建一个隐式展开具有合适类型的可选项实例。

在 init 后面添加惊叹号( init! ) 可以与 init? 或init 互相委托调用。

必要初始化器

初始化器前 添加 required 修饰符,所有该类子类必须实现该初始化器。

class SomeClass {
    required init() {
        // initializer implementation goes here
    }
}

子类重写父类必要初始化器时,必须同样添加 required 修饰符。

class SomeSubclass: SomeClass {
    required init() {
        // subclass implementation of the required initializer goes here
    }
}

通过闭包和函数来设置属性的默认值

当这个属性归属的实例初始化时,闭包或函数就会被调用,并且它的返回值就会作为属性的默认值。

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
    }()
}

注意结尾没有参数的圆括号,为立即执行闭包。闭包内不能读取其他属性值,也不能使用隐式self属性,或调用实例方法。

struct Chessboard {
    let boardColors: [Bool] = {
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        return temporaryBoard
    }()
    func squareIsBlackAt(row: Int, column: Int) -> Bool {
        return boardColors[(row * 8) + column]
    }
}
 
let board = Chessboard()
print(board.squareIsBlackAt(row: 0, column: 1))
// Prints "true"
print(board.squareIsBlackAt(row: 7, column: 7))
// Prints "false"