本笔记主要记录类、结构体、枚举初始化方法定义与实现;

1.初始化函数结构解析

1.不带参数初始化
init()
{
   //initialise the stored properties here
}
2.带参数初始化
init(parameter:type...)
{
   //initialise the stored properties here
}

初始化返回的一般都是类、结构体、枚举本身,所以不需要特殊声明返回值。

2.为什么类、结构体、枚举需要初始化?

我们先从类说起,我们定义了一个类A。

class A{
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
}

编译时发现报错,报错信息:Class A has no initializers;提示我们需要对A进行初始化。

为什么需要对A进行初始化?

因为我们在A中声明的变量Swift是不自动给变量赋初始值的,可选类型是自动设置初始值的;如果需要编译不报错,首先需要给你确定类型的变量,赋初始值。所以,面对报错有三种结局方案:
1.将确定类型的变量,变为Optional类型
2.给确定类型的变量,赋初始值
3.给类添加初始化方法,在函数中,给变量赋初始值

所以,可以根据个人项目情况,选择解决方案。

3.结构体初始化方法定义与实现

3.1自定义初始化方法与默认初始化方法

其实在学习结构体时,已经了解了结构体初始化;结构体本身是带有默认初始化方法的,不需要特殊声明;同时,我们也可以为结构体自定义初始化方法。两种在实现没有区别,我们先看看结构体默认初始化方法。

struct Rect{
    var length : Int
    var breadth : Int
}
var r = Rect(length: 5, breadth: 10)

如果不给结构体中的变量赋值的话,实现的时候会报错;下面的实现现在就会报错。

var r1 = Rect()
//此时给结构体中变量赋初始值后就不会报错了
struct  Rectangle{
    var length : Int = 0
    var breadth : Int = 0
}
var R = Rectangle()//此时length和breadth都是0
var R1 = Rectangle(length: 10, breadth: 5)

然后实现自定义初始化方法

struct Rect2{
    var length : Int
    var breadth : Int
    
    init(_ length: Int, _ breadth: Int) {//不带外部参数;
        self.length =  length
        self.breadth = breadth
    }
    
    init(_ length: Int)//不带外部参数,对初始化方法进行简化
    {
        self.init(length, length)
    }
}
var rr = Rect2(10, 5)
var rr1 = Rect2(15) //initialises the length and breadth to 15

初始化需要将类、结构体中定义的所有没有初始值的变量都在初始化方法中赋初始值。这个包括所有参数的初始化方法被称为指定初始化方法。其他初始化可以调用改方法。

3.2可选初始化

每个初始化是返回类本身,但是有时因为入参与参数值缺少等问题,导致初始化失败,此时我们就可以用可选初始化,来解决初始化失败问题;代码如下:

struct SName{
    let name : String
    init?(name : String){
        if name.isEmpty{return nil}
        self.name = name
    }
}

var name = SName(name: "Bobby")
if name != nil{
    print("init success")
}else{
    print("init failed")
}
name = SName(name: "")
if name != nil{
    print("init success")
}else{
    print("init failed")
}

4.枚举初始化

枚举的初始化只能是可选初始化类型;

enum CharacterExists{
    case A,B
    init?(symbol: Character){
        switch symbol {
        case "A":
            self = .A
        case "B":
            self = .B
        default:
            return nil
        }
    }
}

let ch = CharacterExists(symbol: "C")
if ch != nil{
    print("Init failed. Character doesn't exist")
}

5.类初始化

5.1类初始化的一般形式-指定初始化

必须把类中所有没有初始值的属性,都初始化

class B {
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
    init(a : Int, b : String){
        self.a = a
        self.b = b
    }
}
var b = B(a: 5, b: "Hello Init")

//在初始化方法中,我们也可以改变常量值
class C {
    var a : Int
    var b : String
    var c : Int?
    let website : String
    init(a:Int,b:String,website:String){
        self.a = a
        self.b = b
        self.website = website
    }
}
var c = C(a: 10, b: "Hello. Init", website: "www.huihuang.com")
//此时website  = "www.huihuang.com"

//不带外部参数的初始化
class D {
    var a : Int
    var b : String
    var c : Int?
    let website = "JournalDev"
    init(_ a: Int,_ b: String){
        self.a = a
        self.b = b
    }
}
var d = D(10, "Hello. Init")

5.2便利初始化

便利初始化,也是调用指定初始化,只是我们设定初始值,在init前用Convenience修饰。

class Student{
    var name : String
    var degree : String
    init(name: String,degree: String){
        self.name = name
        self.degree = degree
    }
    convenience init(){
        self.init(name: "Unnamed",degree: "Computer Science")
    }
}
var student = Student()
student.degree//"Computer Science"
student.name//"Unnamed"

5.3类初始化继承、重写

先声明一个父类,然后看子类如果继承与重写父类初始化方法

//父类
enum VehicleType : String{
    case twoWheeler = "TwoWheeler"
    case fourWheeler = "FourWheeler"
}
class Vehicle{
    var vehicleType : VehicleType
    //自定义初始化
    init(vehicleType:VehicleType) {
        self.vehicleType = vehicleType
        print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
    }
    //便利初始化:必须调用自定义初始化函数,参数为自己设定的默认值
    convenience init(){
        self.init(vehicleType:.fourWheeler)
    }
}
var v = Vehicle(vehicleType: .twoWheeler)

//然后我们定义一个子类
//子类定义初始化时,需要先初始化子类的属性,然后调用父类初始化方法
//子类在调用父类自定义初始化方法后,才可以修改父类属性的值
//声明子类的时候,不可以使用父类的初始化方法
//但是子类重写父类初始化方法后,可以使用父类的初始化方法,用override关键字修饰
enum TwoWheelerType : String{
    case scooty = "Scooty"
    case bike = "Bike"
}

class TwoWheeler : Vehicle{
    var twoWheelerType : TwoWheelerType
    var manufacturer :  String
    init(twoWheelerType : TwoWheelerType,manufacturer:String,vType:VehicleType){
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
    }
    //重写父类方法时,也需要先初始化子类属性,然后调用父类初始化方法
    override init(vehicleType: VehicleType) {
        self.twoWheelerType = .bike
        self.manufacturer = "Not defined"
        super.init(vehicleType: vehicleType)
    }
}
var t = TwoWheeler(twoWheelerType: .scooty, manufacturer: "Hero Honda",vType: .twoWheeler)
//打印结果:
//Class TwoWheeler. Scooty manufacturer is Hero Honda
//Class Vehicle. vehicleType is TwoWheeler

var tt = TwoWheeler(vehicleType: .twoWheeler)
//打印结果:Class Vehicle. vehicleType is TwoWheeler

5.4便利构造初始化

便利构造函数,不能被子类调用、重写。
便利构造初始化,可以直接调用子类中自定义初始化函数;并对父类中的属性进行修改。

class TwoWheelerVehicle : Vehicle{
    var twoWheelerType : TwoWheelerType
    var manufacturer :  String
    init(twoWheelerType : TwoWheelerType,manufacturer:String,vType:VehicleType){
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheelerVehicle. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
    }
    //便利构造函数
    override convenience init(vehicleType: VehicleType) {
        self.init(twoWheelerType: .bike, manufacturer: "Not Defined", vType: .twoWheeler)
        self.vehicleType = vehicleType
    }
}

var ttt = TwoWheelerVehicle(twoWheelerType: .scooty, manufacturer: "Hello Hoda", vType: .twoWheeler)
ttt = TwoWheelerVehicle(vehicleType: .twoWheeler)
//打印结果:
//Class TwoWheelerVehicle. Scooty manufacturer is Hello Hoda
//Class Vehicle. vehicleType is TwoWheeler

5.5子类必须实现的初始化方法

required修饰的init方法,必须在子类中实现


class VehicleTwo{
    
    var vehicleType : VehicleType
    
    required init(vehicleType: VehicleType) {
        self.vehicleType = vehicleType
        print("Class Vehicle. vehicleType is \(self.vehicleType.rawValue)\n")
    }
    
    convenience init()
    {
        self.init(vehicleType: .fourWheeler)
    }
}

class TwoWheelerCar : VehicleTwo{
    
    var twoWheelerType : TwoWheelerType
    var manufacturer : String
    
    init(twoWheelerType : TwoWheelerType, manufacturer : String, vType : VehicleType) {
        self.twoWheelerType = twoWheelerType
        self.manufacturer = manufacturer
        print("Class TwoWheeler. \(self.twoWheelerType.rawValue) manufacturer is \(self.manufacturer)")
        super.init(vehicleType: vType)
        
    }
    
     required init(vehicleType: VehicleType) {
        self.manufacturer = "Not Defined"
        self.twoWheelerType = .bike
        super.init(vehicleType: vehicleType)
    }
}

//required convenience

enum FourWheelerType : String
{
    case car = "Car"
    case bus = "Bus"
    case truck = "Truck"
}


class FourWheeler : Vehicle
{
    var fourWheelerType : FourWheelerType
    var name : String
    
    init(fourWheelerType : FourWheelerType, name: String, vehicleType: VehicleType) {
        self.fourWheelerType = fourWheelerType
        self.name = name
        print("Class FourWheeler. \(self.fourWheelerType.rawValue) Model is \(self.name)")
        super.init(vehicleType: vehicleType)
        self.vehicleType = vehicleType
    }
    
    required convenience override init(vehicleType: VehicleType) {
        self.init(fourWheelerType: .bus, name: "Mercedes", vehicleType: vehicleType)
    }
}


class Car : FourWheeler{
    
    var model : String
    
    init(model: String) {
        self.model = model
        print("Class Car. Model is \(self.model)")
        super.init(fourWheelerType: .car, name: self.model, vehicleType: .fourWheeler)
    }
    
    required init(vehicleType: VehicleType)
    {
        self.model = "Not defined"
        print("Class Car. Model is \(self.model)")
        super.init(fourWheelerType: .car, name: self.model, vehicleType: vehicleType)
    }
    
}

5.6自动继承初始化方法

分为两种情况

//1.不要在子类中定义任何指定的初始值设定项
class PeopleName{
    var name : String
    init(n : String){
        self.name = n
    }
}

class StudentName : PeopleName{
    var tutorial : String? = "Swift Initialization"
}
var parentObject = PeopleName(n: "Bobby")
print(parentObject.name)//打印结果:Bobby
var childObjec = StudentName(n : "Bobby Chloe")
print(childObjec.name)//打印结果:Bobby Chole
print(childObjec.tutorial!)//打印结果:Swift Initialization
//2.实现父类的所有指定初始值设定项。所有便利初始值设定项也将自动继承。
class FateherName{
    var name : String
    init(n : String){
        self.name = n
    }
    convenience init(){
        self.init(n : "No name assigned")
    }
}

class ChildName : FateherName{
    var tutorial : String? = "Swift Tutorail"
    override init(n: String) {
        super.init(n: n)
    }
}
var fatherObject = FateherName(n: "Bobby")
print(fatherObject.name)
var daughterObject = ChildName(n: "Chloe")
print(daughterObject.name)
var sonObject = ChildName()
print(sonObject.name)

5.7可选初始化

//可失败的初始值设定项和不可失败的初始值设定项不能具有相同的参数类型和名称
//重写可失败初始化:可失败初始化可以重写为不可失败初始化方法,反之不行;也可以重写为可失败初始化方法
class CName{
    let name : String
    init?(name:String){
        if name.isEmpty{return nil}
        self.name = name
    }
}
var cname = CName(name: "") //nil

class SubName : CName{
    var age : Int
    //重写为不可以失败初始化
    override init(name : String){
        self.age = 23
        super.init(name: name)!
    }
    //重写为可以失败初始化
//    override init?(name: String) {
//        self.age = 23
//        super.init(name: name)
//    }
}
var subNameCannot = SubName(name: "haha")//不可以失败初始化

//var subName  = SubName(name: "")//可失败初始化:nil
posted on 2021-07-09 16:00  蓬松小辉煌  阅读(138)  评论(0编辑  收藏  举报