Swift - 构造器

/*************** 初始化 *******************/
        
        // 在使用 实类,结构体,枚举之前都需要初始化
        // 初始化过程需要给 存储属性设值, 并做其他初始化操作.
        
        // 和oc 不同, swift 初始化并不反回值.
        // 初始化是为了确保这个实类在第一次使用的前已经做好了准备
        
        // 初始化给存储属性设值
        // 类和结构体在初始化时必须给所有存储属性赋值. 存储属性不允许有不确定值得状态
        // 也可以在定义存储属性时给它设一个默认值, 该操作不会触发观察者模式
        struct Fahrenheit{
            var temperature: Double
            init(){
                temperature = 32.0// 初始化设置默认值
            }
        }
        
        var f = Fahrenheit()
        print("The default temperature is \(f.temperature)")
        //Prints "The default temperature is 32.0 Fahrenheit"
        
        
        
        // 设置存储属性默认值
        // 属性申明的时候就设置默认值
        struct FahrenheitA{
            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)
        // boi9lingPointOfWater.temperatureInCelsius is 100.0
        let freezingPointOfWater = Celsius(fromKelvin: 273.15)
        // freezingPointOfWater.temperatureInCelsius is 0.0
        
        
        //-----------参数名 和参数标签-------
        // 在初始化中, 默认 参数名就是标签名, 方法内部和外部都可以用
        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)
        // 报错, Missing argument labels 'red:green:blue:' in call
        
        
        // 那么如何在初始化的时候 不显示参数名呢?
        // 定义初始化方法时 ,用下划线 代表表情参数就可
        
        struct CelsiusA {
            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 = CelsiusA(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 SurveyQuestionA{
            let text: String
            var response:String?
            init(text: String) {
                self.text = text
            }
            
            func ask(){
                print(text)
            }
        }
        let beetsQuestion = SurveyQuestionA(text: "How about beets")
        beetsQuestion.response = "I alse like beets. (But not with cheese)"
        // 在初始化之前 text 的值为空, 初始化时 我们给一个 常量值赋值了
        
        
        
        //--------- 默认的初始化方法----------
        // swift 为 类和结构体提供了默认的初始化方法
        // 这时候 属性都需要设置默认值.
        
        class ShoppingListItem:NSObject{
            var name: String? //默认值 是 nil
            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 就可
        // 类 类型 是可以继承的, 所有他的委托调用毕竟复杂
        // 也可以把 委托调用的 初始化方法 写到 扩展 Extension 中 (后面Extension 内容 中 会提到)
        struct SizeA{
            var width = 0.0, height = 0.0
        }
        
        struct Point{
            var x = 0.0, y = 0.0
        }
        
        struct Rect{
            
            var origin = Point()
            
            var size = SizeA()
            
            init(){}
            
            init(origin: Point, size: SizeA){
                
                self.origin = origin
                
                self.size = size
            
            }
            
            init(center: Point, size: SizeA){
                
                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 的 origin 是 (0.0, 0.0) size is (0.0, 0.0)
        
        let originRect = Rect(origin: Point(x: 2.0, y:2.0), size: SizeA(width: 5.0, height:5.0))
        // originRect 的 origin = (2.0, 2.0)  size = (5.0, 5.0)
        
        let centerRect = Rect(center: Point(x: 4.0, y:4.0), size: SizeA(width: 3.0, height: 3.0))
        // centerRect's origin = (2.5, 2.5) size = (3.0, 3.0)
        
        
        
        // ---------------类 继承 和 初始化 ----------
        // 类的所有存储属性, 包括从父类哪里继承来的属性,在初始时都要一个初始值
        // swfit 有两种方法给存储属性设置设置初始值.
        // 1. 指定初始化
        // 2. 便捷初始化
        
        // -----------指定初始化 和 便捷 初始化 --------
        //http://swifter.tips/init-keywords/
        // Designated 指定初始化时最常用,最主要的初始化方法, 初始化过程中 会给所有存储属性一个初始化值
        // 任何类至少有一个 Designated 指定初始化方法
        // 
        // Convenience 便捷初始化是二等初始化方法
        // 他必须在内部调用一个 Designated 指定初始化方法. 
        // 可以给一些属性设置默认值,可以给一些属性设置初始值
        // 便捷初始化 可有可无
        // 
        // 指定初始化
        //init(parameters){
        //    statements
        //}
        // 便捷初始化
        // convenience init(parameters){
        //      statements
        //}
        
        
        
        // ---------- 类 的初始化 委托------------
        // 3 个准则
        // 1. Designated 初始化方法 必须调用一个自己直接父类的 Designated 初始化方法
        // 2. Convenience 初始化 方法 必须调用另外一个 该类的初始化方法(Convenience 或者 Designated)
        // 3. Convenience 最终还是要调用一个 Designated 初始化方法
        // designate 可以向上调用父类的designate 
        // Conveninece 只能调用该类的 初始化方法.
        
        
        //---------- 类 初始化的两个阶段----------------
        // 第一阶段, 给所有存储属性一个初始值
        // 第二阶段, 在类初始化为实类之前对初始值进行改造
        // 和 oc 初始化不同, oc 初始化时, 所有的属性都是 nil
        
        // 初始化 编译的过程的四个安全检查
        // 1. 在调用父类初始化之前 必须给子类特有的属性设置初始值, 只有在类的所有存储属性状态都明确后, 这个对象才能被初始化
        // 2. 先调用父类的初始化方法,  再 给从父类那继承来的属性初始化值, 不然这些属性值 会被父类的初始化方法覆盖
        // 3. convenience 必须先调用 designated 初始化方法, 再 给属性初始值. 不然设置的属性初始值会被 designated 初始化方法覆盖
        // 4. 在第一阶段完成之前, 不能调用实类方法, 不能读取属性值, 不能引用self
        
        // 第一阶段:
        // - designated 或者 convenience 初始化方法被调用
        // - 实类的内存被分配, 这时内存还没有完全被初始化
        // - 类的 designated 初始化方法确保所有的存储属性有了初始值, 保存这些存储属性的内存被初始化
        // - 初始化方法传递给父类, 由父类完成上面的过程, 存储所有存储属性值
        // - 继续向继承链的上部传递,直到最顶层
        // - 一直到最顶层的类的所有存储属性都被设置了初始值, 说明这个类的内存初四哈哈完成. 整个初始化的第一阶段结束
        
        // 第二阶段
        // - 从继承链顶部到底部, 每个 designated 初始化方法都可以 引用 self, 修改属性值, 调用实类方法.等
        // - 最后 任何 convenience 初始化方法中都可以 定制实类, 引用 self
        
        
        
        // --------------- 初始化的继承和重写 ------------
        //http://www.cnblogs.com/Rinpe/p/5189111.html
        /*
         构造器的继承:
         Swift的子类不会自动继承父类的构造器, 若继承, 则满足如下规则:
         1.如果子类没有提供任何指定构造器, 那么它将自动继承父类的所有指定构造器
         2.如果子类实现了父类所有的指定构造器, 无论如何实现的, 都将自动继承父类的所有便利构造器
         */
        
        /*
         构造器的重写:
         1.子类构造器重写了父类的指定构造器, 必须添加override修饰符
         2.子类中定义的构造器只是和父类中便利构造器的形参列表, 外部形参名相同, 不算重写
         */
        
        /*
         总结:
         1.如果一个子类没有定义任何构造器, 那么它将自动继承父类中的所有构造器
         2.如果一个子类重写父类的所有指定构造器, 那么它将自动继承父类中的所有便利构造器
         3.如果一个子类中任意的构造器和父类的便利构造器一模一样, 不算重写, 创建对象的时候也只会显示子类定义的构造器
         */
        
        // 注意: 即使你重写的是父类的 designated 构造器, 子类也可以写作 convenience 构造器, 即: designated 可以重写为 convenience
        // convenience 构造器 不能被重写
        class Vehicle{
            
            var numberOfWheels = 0
            
            var description: String {
                
                return "\(numberOfWheels) wheels"
                
            }
            
        }
        
        let vehicle = Vehicle()
        
        print("Vehicle: \(vehicle.description)")
        //Vehicle: 0 wheels
        
        class Bicycle: Vehicle{
            override init() {
                
                super.init()
                
                numberOfWheels = 2
            }
            
        }
        
        let bicycle = Bicycle()
        
        print("Bicycle: \(bicycle.description)")
        //Bicycle: 2 wheels
        // 子类可以修改 继承来的变量属性, 不能修改常量属性
        
        
        //-----------构造器自定继承----------
        // swift 默认不继承 构造器
        // 当子类 1 个构造器也没有时, 会自动继承父类所有的构造器
        // 规则1: 当子类没有定义任何构造器, 子类自动继承父类所有designated 构造器
        // 规则2: 当子类实现了父类所有的designated 构造器方法,无论是像规则1那样从父类继承的,还是自定义实现的, 都会自动继承父类所有的 convenience 构造器
   
        
        
        // 关于构造器的实例
        class Food{
            
            var name: String
            
            init(name: String){
                
                self.name = name
            
            }
            
            convenience init(){
                
                self.init(name: "[Unnamed]")
                
            }
            
        }
        
        let namedMeat = Food(name:"Bacon")
        // namedMeat.name = "Bacon"
        
        let mysteryMeat = Food()
        // mysteryMeat.name = "[Unnamed]"
        
        class RecipeIngRedient: Food{
            
            var quantity: Int
            
            init(name: String, quantity: Int){
                
                self.quantity = quantity
                
                super.init(name: name)
            }
              // 这里其实是重写了 父类的 designated 构造器 init(name:String)
              convenience override 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 ShoppingListItemA: RecipeIngRedient{
            
            var purchased = false
            
            var description: String{
                
                var output = "\(quantity) x \(name)"
                
                output += purchased ? "✔" : "✘"
                
                return output
            }
            
        }
        
        var breakfastList = [
            
            ShoppingListItemA(),

            ShoppingListItemA(name: "Bacon"),
            
            ShoppingListItemA(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? 失败时 用return nil 返回
        
        struct AnimalAA{
            
            let species: String
            
            init?(species: String){
                
                if species.isEmpty{return nil}//构造器失败 返回nil
                
                self.species = species //构造器成功不需要 return
            }
            
        }
        
        let someCreature = AnimalAA(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 annonymousCreature = AnimalAA(species: "")
        // annoymousCreature is of type Animal ? , not Animal
        
        if annonymousCreature == nil{
            
            print("The annonymous creature could not be initialized")
            // Prints "The anonymous creature could not be initialized
            
        }
        
        
        
        //------------- 枚举 构造器失败 -------------
        // 当构造枚举的 key 不匹配任何一个 case 时 我们可以定义这枚举类型失败
        
        
        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 TemperatureUnitA: Character{
            case kelvin = "K", celsius = "C", fahrenheit = "F"
        }
        
        let fahrenheitUnitA = TemperatureUnitA(rawValue: "F")
        
        if fahrenheitUnitA != nil{
            print("This is a defined temperature unit, so initialization succeeded.")
        }
        // Prints "This is a defined temperature unit, so initialization succeeded.”

        let unknownUnitB = TemperatureUnitA(rawValue: "X")
        
        if unknownUnitB == 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)
            }
        }
        // 用合法的 quantity 创建构造器
        if let twoSocks = CartItem(name: "sock", quantity: 2){
            
            print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
            
        }
        // Print "Item: sock, quantity: 2"
        
        //使用非法的 quantity 创建构造器
        if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
            
            print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
            
        } else {
            
            print("Unable to initialize zero shirts")
            
        }
        //Print "Unable to initialize zero shirts"
        
        // 使用非法的 name 创建构造器, 父类构造器失败,导致该类构造器失败
        if let oneUnnamed = CartItem(name: "", quantity: 1) {
            
            print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
            
        } else {
            
            print("Unable to initialize zero shirts")
        
        }
        //Prints "Unable to initialize zero shirts"
            
   
    
        //------------ 重写构造器失败 ------------
        // 当父类是可以失败的构造器时
        // 如何确保子类的构造器一定是成功的呢!
        // 只要子类不满足造成父类构造器失败的条件即可
        class Document{
            
            var name: String?
            
            // name 可选值, 可为 nil
            
            init(){}
            
            init?(name: String) {
                
                if name.isEmpty { return nil }
                
                self.name = name
                
            }
            
        }
        
        class AutomaticallyNamedDocument: Document{
            
            override init() {
                
                super.init()

                self.name = "[Untitled]"
                
            }
            
            override init(name: String){
                // 没有调用会让父类构造器失败的 方法 `init(name: String)`
                super.init()
                
                if name.isEmpty {
                    // 给 name 一个默认值,
                    self.name = "[Untitled]"
                    
                } else {
                    
                    self.name = name
                    
                }
                
            }
            
        }
    
        
        class UntitledDocument: Document{
            
            override init() {
                // 如果这里写作 super.init(name: "") 编译器回报错, 因为这样写没意义
                super.init(name: "[Untitled]")!// 强制解包
                
            }
            
        }
    
    
        // ------- 父类构造器可能失败,子类构造器一定成功 init!-----
        // 当使用 init! 时, 必须确定该类一定有值, 如果该类为 nil 则会抛出异常
        
        
        // --------- 要求实现的构造器 ------------
        // 用关键字 required 修饰的构造器是子类必须重写的的构造器
        // 重写 required 的构造器 不需要 override 关键字
        
        class SomeClass {
            
            required init() {
                
            
            }
        
        }
        
        class SomeSubclass: SomeClass{
            //重写父类构造器 没有 override
            required init() {
                //
            }
            
        }
    
        
        
        // ---------- 用 闭包 和 方法 给属性设置默认值
        
//        class SomeClassA {
//            
//            let someProperty: Sometype = {
//                // create a default value for someProperty inside this closure
//                // someValue must be of the same type as SomeType”
//                
//                return someValue
//            }()
//            
//        }
    
        // 上面的代码, 属性 someProperty 默认值是闭包的返回值.
        // 如果没有最后 的小括号() 属性 someProperty 的 值 是一个闭包(不是返回值)
        // 小括号还有一个作用, 让闭包立即运行, 返回结果
        
        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))
        //true
        
        print(board.squareIsBlackAt(row: 7, column: 7))
        //false
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容