swift_024(Swift 的构造过程)

//***********swift学习之24--构造过程--***************************


/*

 构造过程:将某个类/结构体/枚举类型实例化而进行的准备过程。

 这个过程包含:为实例中的每个属性设置初始值和为其执行必要的准备和初始化任务。

 

 Swift 构造函数使用 init()方法。(构造器)

  Objective-C 中的构造器不同,Swift 的构造器无需返回值,它们的主要任务是保证新实例在第一次使用前完成正确的初始化。

 

 类实例也可以通过定义析构器(deinitializer)在类实例释放之前执行清理内存的工作。

 存储型属性的初始赋值

 类和结构体在实例创建时,必须为所有存储型属性设置合适的初始值。

 存储属性在构造器中赋值时,它们的值是被直接设置的,不会触发任何属性观测器。

 

 存储属性在构造器中赋值流程:

 a:创建初始值。

 b:在属性定义中指定默认属性值。

 c:初始化实例,并调用 init() 方法。

 */



// 实例

// 初始化:以下结构体定义了一个不带参数的构造器 init,并将存储型属性 length breadth 的值初始化为 6 12

struct rectangle {

    var length: Double

    var breadth: Double

    init() {

        // 以在构造器中为存储型属性设置 初始值

        length = 6

        breadth = 12

    }

}

var area = rectangle()

print("矩形面积为 \(area.length*area.breadth)")



// 默认属性值

// 在属性声明时为其设置 默认值。

// 使用默认值能让你的构造器更简洁、更清晰,且能通过默认值自动推导出属性的类型。


struct rectangle1 {

    // 设置默认值

    var length = 6

    var breadth = 12

}

var area11 = rectangle1()

print("矩形的面积为 \(area11.length*area11.breadth)")




// 带参数的构造器 如下所示:


// circle 圆的面积

struct circle {

    var pai = 3.14

    var radius: Double

    var area: Double

    

    // 构造器1

    init(fromRadius radius: Double) {

        self.radius = radius

        area = pai * radius * radius

    }

    

    // 构造器2

    init(fromR r: Double) {

        self.radius = r

        area = pai * radius * radius

    }

}


let ar = circle(fromRadius:2)

print("面积为: \(ar.area)")


let are = circle(fromR:10)

print("面积为: \(are.area)")




// 没有外部名称参数

// 如果你不希望为构造器的某个参数提供外部名字,你可以使用下划线_来显示描述它的外部名。


struct Rectanglett {

    let length: Double?

    

    init(frombreadth breadth: Double) {

        length = breadth * 10

    }

    

    init(frombre bre: Double) {

        length = bre * 30

    }

    //不提供外部名字

    init(_ area: Double) {

        length = area

    }

}


// 调用不提供外部名字

let rectarea = Rectanglett(180.0)

print("面积为: \(rectarea.length)")


/*

 只要在构造过程结束前常量的值能确定,你可以在构造过程中的任意时间点修改常量属性的值。

 对某个类实例来说,它的常量属性只能在定义它的类的构造过程中修改;不能在子类中修改。

 尽管 length 属性现在是常量,我们仍然可以在其类的构造器中设置它的值:

 */




// 结构体的逐一成员构造器

// 如果结构体对所有存储型属性提供了默认值且自身没有提供定制的构造器,它们能自动获得一个逐一成员构造器。

// 我们在调用逐一成员构造器时,通过与成员属性名相同的参数名进行传值来完成对成员属性的初始赋值。

// 下面例子中定义了一个结构体 Rectangle,它包含两个属性 length breadthSwift 可以根据这两个属性的初始赋值100.0 200.0自动推导出它们的类型Double

struct Rectangleaa {

    var length = 100.0, breadth = 200.0

}

let areaaa = Rectangleaa(length: 24.0, breadth: 32.0)


print("矩形的长: \(areaaa.length)")

print("矩形的宽: \(areaaa.breadth)")


// 由于这两个存储型属性都有默认值,结构体 Rectangle 自动获得了一个逐一成员构造器 init(width:height:) 你可以用它来为 Rectangle 创建新的实例。



/*

 值类型的构造器代理

 构造器可以通过调用其它构造器来完成实例的 部分 构造过程。这一过程称为构造器代理,它能减少多个构造器间的代码重复。

 以下实例中,Rect 结构体调用了 Size Point 的构造过程

 */


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)

    }

}



// originsize属性都使用定义时的默认值Point(x: 0.0, y: 0.0)Size(width: 0.0, height: 0.0)

let basicRect = Rect()

print("Size 结构体初始值: \(basicRect.size.width, basicRect.size.height) ")

print("Rect 结构体初始值: \(basicRect.origin.x, basicRect.origin.y) ")


// originsize的参数值赋给对应的存储型属性

let originRect = Rect(origin: Point(x: 2.0, y: 2.0),

                      size: Size(width: 5.0, height: 5.0))


print("Size 结构体初始值: \(originRect.size.width, originRect.size.height) ")

print("Rect 结构体初始值: \(originRect.origin.x, originRect.origin.y) ")



//先通过centersize的值计算出origin的坐标。

//然后再调用(或代理给)init(origin:size:)构造器来将新的originsize值赋值到对应的属性中

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),

                      size: Size(width: 3.0, height: 3.0))


print("Size 结构体初始值: \(centerRect.size.width, centerRect.size.height) ")

print("Rect 结构体初始值: \(centerRect.origin.x, centerRect.origin.y) ")




// 指定构造器实例

// 初始化类中提供的所有属性,并根据父类链往上调用父类的构造器来实现父类的初始化。

// 每一个类都必须拥有至少一个指定构造器

class mainClasstt {

    var no1 : Int // 局部存储变量

    init(no1 : Int) {

        self.no1 = no1 // 初始化

    }

}

class subClasstt : mainClasstt {

    var no2 : Int // 新的子类存储变量

    init(no1 : Int, no2 : Int) {

        self.no2 = no2 // 初始化

        super.init(no1:no1) // 初始化超类

    }

}


let res = mainClasstt(no1: 10)

let res2 = subClasstt(no1: 10, no2: 20)


print("res : \(res.no1)")

print("res2 : \(res2.no1)")

print("res2 : \(res2.no2)")




// 构造器的继承和重载

// Swift 中的子类不会默认继承父类的构造器。

// 父类的构造器仅在确定和安全的情况下被继承。


// 重写一个父类指定构造器时,override修饰符。

class FatherClass {

    var corners = 4

    var description: String {

        return "\(corners) "

    }


}


let rectanglett = FatherClass()


print("矩形:\(rectanglett.description)")


class SonClass:FatherClass {

    

//    override init () { //重载构造器

//        super.init()

//        corners = 5   // 父类的属性

//    }

}


let sonClass = SonClass()

print("corners: \(sonClass.corners)")

print("五角型: \(sonClass.description)")





// 指定构造器和便利构造器实例 的例子

class MainClass {

    var name: String

    

    init(name: String) {

        self.name = name

    }

    

    convenience init() {

        self.init(name: "[匿名]")

    }

}

let main = MainClass(name: "Runoob")

print("MainClass 名字为: \(main.name)")


let main2 = MainClass()

print("没有对应名字: \(main2.name)")


class ChildClass: MainClass {

    var count: Int

    init(name: String, count: Int) {

        self.count = count

        super.init(name: name)

    }

    

    override convenience init(name: String) {

        self.init(name: name, count: 1)

    }

}


let sub = ChildClass(name: "Runoob")

print("MainClass 名字为: \(sub.name)")


let sub2 = ChildClass(name: "Runoob", count: 3)

print("count 变量: \(sub2.count)")



// 可失败构造器 init!

// 如果一个类,结构体或枚举类型的对象,在构造自身的过程中有可能失败,则为其定义一个可失败构造器。

// 通常在init关键字后添加问号的方式(init?)来定义一个可失败构造器,但你也可以使用通过在init后面添加惊叹号的方式来定义一个可失败构造器(init!)。实例如下:

struct StudRecord {

    let stname: String

    

    init!(stname: String) {

        if stname.isEmpty {return nil }

        self.stname = stname

    }

}


let stmark = StudRecord(stname: "Runoob")

if let name = stmark {

    print("指定了学生名")

}


let blankname = StudRecord(stname: "")

if blankname == nil {

    print("学生名为空")

}




// 三种类型的可失败构造器

// a:结构体 -- 可失败构造器

// 1.变量初始化失败可能的原因有:

// 2.传入无效的参数值。

// 3.缺少某种所需的外部资源。

// 4.没有满足特定条件。



/*

 实例

 下例中,定义了一个名为Animal的结构体,其中有一个名为species()的,String类型的常量属性。

 同时该结构体还定义了一个,带一个String类型参数species,可失败构造器。这个可失败构造器,被用来检查传入的参数是否为一个空字符串,如果为空字符串,则该可失败构造器,构建对象失败,否则成功。

 */


struct Animal {

    let species: String

    init?(species: String) {

        if species.isEmpty { return nil }

        self.species = species

    }

}


// 通过该可失败构造器来构建一个Animal的对象,并检查其构建过程是否成功

// someCreature 的类型是 Animal? 而不是 Animal

let someCreature = Animal(species: "长颈鹿")


// 打印 "动物初始化为长颈鹿"

if let giraffe = someCreature {

    print("动物初始化为\(giraffe.species)")

}





// 枚举类型的可失败构造器

/*

 你可以通过构造一个带一个或多个参数的可失败构造器,来获取枚举类型中特定的枚举成员。

 实例

 下例中,定义了一个名为TemperatureUnit的枚举类型。其中包含了三个可能的枚举成员(KelvinCelsius,和 Fahrenheit)和一个被用来找到Character值所对应的枚举成员的可失败构造器:

 */


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("这是一个已定义的温度单位,所以初始化成功。")

}


let unknownUnit = TemperatureUnit(symbol: "X")

if unknownUnit == nil {

    print("这不是一个已定义的温度单位,所以初始化失败。")

}




// 类的可失败构造器

/*

 值类型(如结构体或枚举类型)的可失败构造器,对何时何地触发构造失败这个行为没有任何的限制。

 但是,类的可失败构造器只能在所有的类属性被初始化后和所有类之间的构造器之间的代理调用发生完后触发失败行为。

 实例

 下例子中,定义了一个名为 StudRecord 的类,因为 studname 属性是一个常量,所以一旦 StudRecord 类构造成功,studname 属性肯定有一个非nil的值。

 */


class StuRecord {

    let studname: String!

    init?(studname: String) {

        self.studname = studname

        if studname.isEmpty {

            print("构造失败")

            return nil

        }

    }

}


var strParame = "失败构造器"

strParame = ""

if let stname = StuRecord(studname: strParame) {

    print("模块为 \(stname.studname)")

}



// 覆盖(重写)一个可失败构造器

/*

 子类的可失败构造器 可以 重写父类的可失败构造器。

 也可以用子类的非可失败构造器 重写父类的可失败构造器。

 你可以用一个非可失败构造器覆盖一个可失败构造器,但反过来却行不通。

 一个非可失败的构造器永远也不能代理调用一个可失败构造器。

 实例

 以下实例描述了可失败与非可失败构造器:

 

 */


class Planet {

    var name: String

    

    init(name: String) {

        self.name = name

    }

    

    convenience init() {

        self.init(name: "[No Planets]")

    }

}

let plName = Planet(name: "Mercury")

print("行星的名字是: \(plName.name)")


let noplName = Planet()

print("没有这个名字的行星: \(noplName.name)")


class planets: Planet {

    var count: Int

    

    init(name: String, count: Int) {

        self.count = count

        super.init(name: name)

    }

    

    override convenience init(name: String) {

        self.init(name: name, count: 1)

    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值