Swift基礎-06(構造函數)

1.關于命名空間

Objective-C 沒有命名空間的,在應用開發時,所有的代碼和引用的靜態庫最終都會被編譯到同一個域和二進制中。這樣的后果是一旦我們有重復的類名的話,就會導致編譯時的沖突和失敗。為了避免這種事情的發生,Objective-C 的類型一般都會加上兩到三個字母的前綴,比如 Apple 保留的 NS和 UI 前綴,各個系統框架的前綴 SK (StoreKit), CG (CoreGraphic) 等。Objective-C 社區的大部分開發者也遵守了這個約定,一般都會將自己名字縮寫作為前綴,把類庫命名為 AFNetworking 或者 MBProgressHUD 這樣。這種做法可以解決部分問題,至少我們在直接引用不同人的庫時沖突的概率大大降低了,但是前綴并不意味著不會沖突,有時候我們確實還是會遇到即使使用前綴也仍然相同的情況。另外一種情況是可能你想使用的兩個不同的庫,分別在它們里面引用了另一個相同的很流行的第三方庫,而又沒有更改名字。在你分別使用這兩個庫中的一個時是沒有問題的,但是一旦你將這兩個庫同時加到你的項目中的話,這個大家共用的第三方庫就會和自己發生沖突了。
在 Swift中,由于可以使用命名空間了,即使是名字相同的類型,只要是來自不同的命名空間的話,都是可以和平共處的。swift中的命名空間的使用不是一個項目,而是需要跨項目,在一個項目中,都是一個命名空間,在同一個命名空間下,所有全局變量或者函數共享,不需要import,從swift開始,官方更多的建議大家使用pod來管理第三方框架(不然拿進來一個框架,整個項目哪哪都能使)

2.構造函數 以及 override 重寫
/**
 1.給自己的屬性分配空間并且設置初始值
 2.調用父類的構造函數,給父類的屬性分配空間設置初始值
  ONObject 沒有屬性,只有一個成員變量 ?"isa"
 3.調用父類的構造函數,給父類的屬性分配空間設置初始值
 上面兩步的操作與OC中是相反的,OC中是先調用父類的,然后在為屬性賦值
 4.如果重載了構造函數,并且沒有實現父類的init方法,系統不再提供init()方法,
 */

class Person: NSObject {
    
    // 'Person' cannot be constructed because it has no accessible initializers
    // person類 沒有初始化構造器,構造函數,可以有多個,默認是 init
    var name: String
    
    // 構造函數不需要寫 fun
    // override 重寫
    // 1. 父類存在相同的方法
    // 2. 子類重新編寫父類方法中的實現
    override init() {
        
        // 非 option 屬性,都必須在構造函數中設置初始值,從而保證對象在被實例化的時候,屬性都被正確初始化,
        // 在調用父類的構造函數之前,必須保證本類的屬性都已經初始化完成
        name = "呵呵呵";
        print("Person - init")

        super.init()
    }
    
    // 重載 函數名相同,但是參數和個數不同
    // 重載可以給自己的屬性外部設置初始值
    // OC是沒有重載的, initWithXXX
    init(name: String) {
        
        // 使用參數的name 設置給屬性
        self.name = name
        
        super.init()
    }
} 

3.遍歷構造器

指定構造器是類中最主要的構造器。一個指定構造器將初始化類中提供的所有屬性,并根據父類鏈往上調用父類的構造器來實現父類的初始化。
便利構造器是類中比較次要的、輔助型的構造器。你可以定義便利構造器來調用同一個類中的指定構造器,并為其參數提供默認值。你也可以定義便利構造器來創建一個特殊用途或特定輸入值的實例?!?/p>

類的構造器代理規則
  • 規則 1
    指定構造器必須調用其直接父類的的指定構造器。
    指定構造器

  • 規則 2
    便利構造器必須調用同類中定義的其它構造器。

  • 規則 3
    便利構造器必須最終導致一個指定構造器被調用。

  • 規則4
    convenience 的初始化方法是不能被子類重寫

一個更方便記憶的方法是:
指定構造器必須總是向上代理
便利構造器必須總是橫向代理

4.可失敗的構造器

如果一個類、結構體或枚舉類型的對象,在構造過程中有可能失敗,則為其定義一個可失敗構造器。這里所指的“失敗”是指,如給構造器傳入無效的參數值,或缺少某種所需的外部資源,又或是不滿足某種必要的條件等。

為了妥善處理這種構造過程中可能會失敗的情況。你可以在一個類,結構體或是枚舉類型的定義中,添加一個或多個可失敗構造器。其語法為在init關關鍵字后面添加問號(init?)。

注意
可失敗構造器的參數名和參數類型,不能與其它非可失敗構造器的參數名,及其參數類型相同。

可失敗構造器會創建一個類型為自身類型的可選類型的對象。你通過return nil語句來表明可失敗構造器在何種情況下應該“失敗”。

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

注意
嚴格來說,構造器都不支持返回值。因為構造器本身的作用,只是為了確保對象能被正確構造。因此你只是用return nil表明可失敗構造器構造失敗,而不要用關鍵字return來表明構造成功。

    let someCreature = Animal(species: "Giraffe")
        if let giraffe = someCreature {
            print("An animal was initialized with a species of \(giraffe.species)")
        }
        
        let someCreature2 = Animal(species: "")
        // someCreature 的類型是 Animal? 而不是 Animal
        print(someCreature ?? ()) // 輸出結果()
        guard let giraffe = someCreature else {
            print("類型不匹配") // 輸出結果 類型不匹配
            return
        }
  • 枚舉類型的可失敗構造器
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
        }
    }
}
5.必要構造器

在類的構造器前添加required修飾符表明所有該類的子類都必須實現該構造器:

class SomeClass {
    required init() {
        // 構造器的實現代碼
    }
}

在子類重寫父類的必要構造器時,必須在子類的構造器前也添加required修飾符,表明該構造器要求也應用于繼承鏈后面的子類。在重寫父類中必要的指定構造器時,不需要添加override修飾符:

class SomeSubclass: SomeClass {
    required init() {
        // 構造器的實現代碼
    }
}

注意
如果子類繼承的構造器能滿足必要構造器的要求,則無須在子類中顯式提供必要構造器的實現。

6.通過閉包或者函數設置屬性的默認值

如果某個存儲型屬性的默認值需要一些定制或設置,你可以使用閉包或全局函數為其提供定制的默認值。每當某個屬性所在類型的新實例被創建時,對應的閉包或函數會被調用,而它們的返回值會當做默認值賦值給這個屬性。

這種類型的閉包或函數通常會創建一個跟屬性類型相同的臨時變量,然后修改它的值以滿足預期的初始狀態,最后返回這個臨時變量,作為屬性的默認值。

class SomeClass {
    let someProperty: SomeType = {
        // 在這個閉包中給 someProperty 創建一個默認值
        // someValue 必須和 SomeType 類型相同
       return someValue
    }()
}

注意閉包結尾的大括號后面接了一對空的小括號。這用來告訴 Swift 立即執行此閉包。如果你忽略了這對括號,相當于將閉包本身作為值賦值給了屬性,而不是將閉包的返回值賦值給屬性?!?/p>

注意
如果你使用閉包來初始化屬性,請記住在閉包執行時,實例的其它部分都還沒有初始化。這意味著你不能在閉包里訪問其它屬性,即使這些屬性有默認值。同樣,你也不能使用隱式的self屬性,或者調用任何實例方法。

7.使用KVC屬性賦值,以及后期使用字典轉模型框架,我們的模型應該如何定義?
/**
 1.定義模型屬性的時候,如果是對象,通常定義成可選的
 - 在需要的時候創建,避免寫構造函數 ,可以簡化代碼

 2.如果是基本數據類型,不能設置成可選的,必須要設置初始值,否者KVC會崩潰
 
 3.使用KVC設置數值的時候,數值不能是private的
 
 4.使用KVC之前,應該調用super.init 保證對象實例化完成
 
 */

class Person: NSObject {

    var name: String?

    // 這種寫法會報錯
    // 使用KVC提示無法找到 age這個KEY
    // 原因:Int是一個基本數據類型的結構體,OC中沒有,OC中只有基本數據類型
//    var age: Int?
    
    var age: Int = 0
    
    // this class is not key value coding-compliant for the key title.'
    // 因為這個屬性是私有的,使用KVC設置值的時候,同樣無法設置,會崩潰
//    private var title: String?
    
    var title: String?
        
    init(dict: [String: Any]) {
    
        super.init()
        
        // Use of 'self' in method call 'setValuesForKeys' before super.init initializes self
        // 使用self的方法 setValuesForKeys 之前,應該調用 super.init方法
        // KVC的方法是OC的方法。在運行時給對象發送消息
        // 要求對象已經實例化完成
        setValuesForKeys(dict)
    }
    
    override func setValue(_ value: Any?, forUndefinedKey key: String) {
        // 注意這里不能調用父類的方法,不能將父類的代碼完全覆蓋,這樣才不會崩潰
//        super.setValue(value, forUndefinedKey: key)
    }
}

       // 我們沒有定義XXX這個key的屬性,所以會崩潰,如果解決這個問題,在對象中,重寫
        // override func setValue(_ value: Any?, forUndefinedKey key: String) 這個方法
        let stu2 = Student(dict: ["name": "洋蔥", "age": 11, "title": "Boss", "no": "110", "XXX": "yyy"])
        print("\(stu2.name ?? "") \(stu2.age) \(stu2.no ?? "")")

4.使用runtime獲取對象的屬性,這個和OC中的使用姿勢基本一致
class Student: Person {

    var no: String?
    var bithday: String?
    var address: String?
    var height: Int = 180

    class func getpropertiesList() ->[String] {
        
        var count: UInt32 = 0
        
        var arrM: [String] = []
        
        // 獲取類的屬性列表,返回屬性列表的數組,可選項
        let list = class_copyPropertyList(self, &count)
        
        print("屬性個數:\(count)")
        // 遍歷數組
        for i in 0..<Int(count) {
            
            //根據下標獲取屬性
            let pty = list?[i]
            
            //獲取屬性的名稱<C語言字符串>
            //轉換過程:Int8 -> Byte -> Char -> C語言字符串
            let cName = property_getName(pty!)
            
            //轉換成String的字符串
            let name = String(utf8String: cName!)
            
            arrM.append(name!)
            
            print("-----\(name!)")
        }
        free(list) //釋放list
        return arrM
    }

    // 使用guard let來實現
    class func propertyList() -> [String] {
        var count: UInt32 = 0
        var arrM: [String] = []

        // 獲取類的屬性列表,返回屬性列表的數組,可選項
        let list = class_copyPropertyList(self, &count)
        print("屬性個數:\(count)")
        
        for i in 0..<Int(count) {
            // 使用guard語法,一次判斷每一項是否有值,只要有一項為nil,就不再執行后續的代碼
            guard let pty = list?[i],
                let cName = property_getName(pty),
                let name = String(utf8String: cName)
                else {
                    //繼續遍歷下一個
                    continue
            }
            print(name)
            arrM.append(name)
        }
        free(list)
        return arrM
    }
}

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容