認(rèn)識(shí)Swift系列6之結(jié)構(gòu)體和類

    // 1.結(jié)構(gòu)體
    func test_struct() {
        // 在swift標(biāo)準(zhǔn)庫(kù)中,絕大數(shù)公開的類都是結(jié)構(gòu)體,枚舉和類只占一小部分
        // Bool、Int、Double、String、Array、Dictionary等常見(jiàn)類型都是結(jié)構(gòu)體
        
        struct Date {
            var year: Int
            var month: Int
            var day: Int
            
            var stringDesc: String {
                get {
                    return String(format: "%04d-%02d-%02d", year, month, day)
                }
            }
        }
        // 編譯器會(huì)默認(rèn)為結(jié)構(gòu)體生成一個(gè)初始化器,參數(shù)包含所有的存儲(chǔ)屬性
        let date = Date(year: 2019, month: 7, day: 11)
        print("Date is \(date)")
        print("Datedesc is \(date.stringDesc)")
        
        // 編譯器根據(jù)情況自動(dòng)為結(jié)構(gòu)體生成不同的的初始化器
        // 具體情況視成員屬性而定,宗旨:所有存儲(chǔ)屬性創(chuàng)建出來(lái)都能被初始化
        struct Point1 {
            var x: Int
            var y: Int
            // 自動(dòng)生成(保證x和y能被初始化)
            // Point1(x: <#T##Int#>, y: <#T##Int#>)
        }
        let p1 = Point1(x: 1, y: 1)
        
        struct Point2 {
            var x: Int = 0
            var y: Int
            // 自動(dòng)生成(保證y能被初始化)
            // Point1(x: <#T##Int#>, y: <#T##Int#>)
            // Point2(x: <#T##Int#>)
        }
        let p21 = Point2(x: 2, y: 2)
        let p22 = Point2(y: 2)
        
        struct Point3 {
            var x: Int = 0
            var y: Int = 0
            // 自動(dòng)生成(x和y都已經(jīng)初始化了,不許要在保證,因此可以生成一下幾個(gè)構(gòu)造方法)
            // Point3()
            // Point3(x: <#T##Int#>, y: <#T##Int#>)
            // Point3(x: <#T##Int#>)
            // Point3(y: <#T##Int#>)
        }
        let p31 = Point3()
        let p32 = Point3(x: 2, y: 2)
        let p33 = Point3(x: 2)
        let p34 = Point3(y: 3)
        
        // 當(dāng)自己定義了初始化函數(shù)后,編譯器不會(huì)再自動(dòng)生成其它初始化函數(shù)
        struct Point4 {
            var x: Int = 0
            var y: Int = 0
            
            // Point4(x: <#T##Int#>, y: <#T##Int#>)
            init(x: Int, y: Int) {
                self.x = x
                self.y = y
            }
            
            // 由于自定義了初始化器,以下三個(gè)構(gòu)造器編譯器不會(huì)生成
            // Point4()
            // Point4(x: <#T##Int#>)
            // Point4(y: <#T##Int#>)
        }
        let p41 = Point4(x: 2, y: 2)
        
        // 初始化成員值和構(gòu)造器的本質(zhì)
        /**
         事實(shí)上,雖然Test1中在定義成員的時(shí)候給了初始值,但a和b發(fā)生初始化的時(shí)機(jī)在init方法中
         即Test1中會(huì)自動(dòng)生成類似Test2中的init方法,Test1和Test2完全等價(jià)
         */
        struct Test1 {
            var a: Int = 0
            var b: Int = 0
        }
        let t1 = Test1()
        struct Test2 {
            var a: Int
            var b: Int
            init() {
                self.a = 0
                self.b = 0
            }
        }
        let t2 = Test2()
    }
    test_struct()
    
    // 2.類
    func test_class() {
        // 類在初始化成員值時(shí)的原理和結(jié)構(gòu)體相同,都是在無(wú)參init方法中
        // 默認(rèn)情況下,編譯器不會(huì)幫類生成初始化構(gòu)造器
        /**
         class Size1 {
            var w: Int
            var h: Int
            // 注意:該類沒(méi)有任何構(gòu)造器
         }
         */
        
        /**
         class Size2 {
            var w = 10
            var h: Int
         }
         */
        
        // 當(dāng)且僅當(dāng)類的所有成員都有初始值的時(shí)候,編譯器才會(huì)為類生成無(wú)參構(gòu)造方法
        class Size3 {
            var w = 10
            var h = 20
        }
        let s3 = Size3()
        
        // 同結(jié)構(gòu)體,一下兩段代碼完全等效[Size4 和 Size5 等效]
        class Size4 {
            var a: Int = 0
            var b: Int = 0
        }
        let s4 = Size4()
        class Size5 {
            var a: Int
            var b: Int
            init() {
                self.a = 0
                self.b = 0
            }
        }
        let s5 = Size5()
    }
    test_class()
    
    // 3.結(jié)構(gòu)體和類的本質(zhì)區(qū)別
    func test_struct_class() {
        // (1)結(jié)構(gòu)和枚舉:值類型
        // 創(chuàng)建對(duì)象,在哪里創(chuàng)建對(duì)象,就在哪里開辟對(duì)象需要的內(nèi)存空間
        
        // (2)類:引用類型(指針類型)
        // 創(chuàng)建對(duì)象,對(duì)象需要的內(nèi)存通常開辟堆空間,而在創(chuàng)建的地方使用一個(gè)指針指向該堆空間
        
        // 值類型
        struct sPoint1 {
            var x = 10
            var y = 30
        }
        let sp1 = sPoint1()
        /**
         sp1 的結(jié)構(gòu)
         ┏━━━━━━━┓
         ┃ x(10) ┃
         ┃ y(30) ┃
         ┗━━━━━━━┛
         如果在函數(shù)內(nèi)部創(chuàng)建sp1,則在棧空間開辟 16個(gè)字節(jié)
         如果在全局區(qū)創(chuàng)建sp1,則在數(shù)據(jù)段開辟 16個(gè)字節(jié)
         如果sp1是類的成員變量,則在堆空間開辟 16個(gè)字節(jié)
         */
        print("sPoint1 sp1 size:\(MemoryLayout.size(ofValue: sp1))")
        
        class cPoint1 {
            var x = 10
            var y = 30
        }
        let cp1 = cPoint1()
        /**
         cp1 的結(jié)構(gòu)
         ┏━━━━━━━┓
         ┃ cp1   ┃     
         ┃(指針)  ------> 堆空間
         ┗━━━━━━━┛     ┏━━━━━━━━━━━━━┓
                       ┃ classInfo   ┃
                       ┃ retainCount ┃
                       ┃    x(10)    ┃
                       ┃    y(30)    ┃
                       ┗━━━━━━━━━━━━━┛
         這里,cp1是一個(gè)指針,同樣,cp1可能在??臻g、堆空間、全局區(qū)
         但是 cp1指向的對(duì)象,一定在堆空間
         因此cp1占用8個(gè)字節(jié),cp1指向的對(duì)象占用32個(gè)字節(jié)
         */
        print("cPoint1 cp1 size:\(MemoryLayout.size(ofValue: cp1))")
        print("cPoint1 cp1 obj size:\(class_getInstanceSize(type(of: cp1)))")
        
        // (3)值類型的賦值(實(shí)際上是深拷貝:Copy On Write)
        let sp2 = sp1 // 這里實(shí)際上會(huì)將sp1的內(nèi)存拷貝一份到新的sp2空間
        var sp3 = sp1 // 同上
        // 不過(guò)在swift標(biāo)準(zhǔn)庫(kù)中,為了提升性能,String、Array、Dictionary、Set等采取了Copy On Write技術(shù)
        // 該技術(shù)意思是,只有被拷貝的副本真正需要執(zhí)行寫(修改)操作的時(shí)候,才會(huì)進(jìn)行深拷貝操作
        // 不過(guò)該操作只針對(duì)swift標(biāo)準(zhǔn)庫(kù)類型
        // 所以在我們不需要修改類型時(shí),盡量使用let定義,這樣編譯器直接不會(huì)進(jìn)行深拷貝操作
        
        // 注意:
        var sp4 = sPoint1(x: 1, y: 2)
        sp4 = sPoint1(x: 3, y: 5)
        /**
         sp4 的結(jié)構(gòu)
         ┏━━━━━━━━━━━━━━━━━┓         ┏━━━━━━━━━━━━━━━━━┓
         ┃0x1000000 x(1)   ┃ ------> ┃0x1000000 x(3)   ┃
         ┃0x1000008 y(2)   ┃         ┃0x1000008 y(5)   ┃
         ┗━━━━━━━━━━━━━━━━━┛         ┗━━━━━━━━━━━━━━━━━┛
         //該操作實(shí)際上類似于深拷貝,sp4不會(huì)開辟新空間,而是值覆蓋
         */
        
        // (4)引用類型的賦值(淺拷貝,即拷貝內(nèi)存地址:指針地址)
        let cp2 = cp1
        // 該操作只會(huì)讓cp2擁有和cp1同樣的指針地址
        // 即兩個(gè)指針指向同一個(gè)對(duì)象,雖然cp2擁有cp1相關(guān)信息,但并不擁有獨(dú)立空間
    }
    test_struct_class()
    
    
    // 4.let 對(duì)值類型和引用類型的區(qū)別
    func test_let_for_struct_class() {
        struct Point {
            var x = 1
            var y = 1
        }
        class Size {
            var x = 1
            var y = 1
            
            init(x: Int, y: Int) {
                self.x = x
                self.y = y
            }
        }
        
        let p = Point(x: 5, y: 4)
        // p.x = 8 // 報(bào)錯(cuò)
        
        let s = Size(x: 5, y: 4)
        s.x = 8
        /** 對(duì)比可知
         對(duì)于let修飾的:
           如果是值類型,那么該對(duì)象本身和內(nèi)部成員都不可修改
           如果是引用類型,那么指針指向不可修改,但是指向的對(duì)象可以修改
         
         可以粗暴的這樣理解
            對(duì)于值類型 p 被 let 修飾,由于p的成員都在let之后,則不可修改
            對(duì)于引用類型 s 被 let 修飾,s的在let之后,但s指向的對(duì)象卻在另一個(gè)空間,不歸let管
         */
    }
    test_let_for_struct_class()
    
    
    // 5.嵌套類型和方法
    func test_nest_func() {
        // 嵌套
        struct A {
            enum A1 {
                case a11, a12, a13, a14
            }
            enum A2: Int {
                case a21 = 2, a22, a23, a24
            }
        }
        var a1 = A.A1.a13
        a1 = .a14
        
        // 類、結(jié)構(gòu)體、枚舉 都可以定義方法
        class Size {
            var w = 10
            var h = 10
            
            func show(){
                print("Size w = \(w), h = \(h)")
            }
        }
        struct Point {
            var x = 10
            var y = 10
            
            func show(){
                print("Point w = \(x), h = \(y)")
            }
        }
        enum TestEnum {
            case a1, a2, a3
            func show(){
                print("A is \(self)")
            }
        }
        
        let s = Size()
        s.show()
        
        let p = Point()
        p.show()
        
        let e = TestEnum.a1
        e.show()
    }
    test_nest_func()
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容