swift-可選鏈式調用

 /*
     ? 使用可選鏈式調用代替強制展開
     ? 為可選鏈式調用定義模型類
     ? 通過可選鏈式調用訪問屬性
     ? 通過可選鏈式調用調用方法
     ? 通過可選鏈式調用訪問下標
     ? 連接多層可選鏈式調用
     ? 在方法的可選返回值上進行可選鏈式調用
     */
    
    //可選鏈式調用是一種可以在當前值可能為 nil 的可選值上請求和調用屬性、方法及下標的方法。如果可選值有 值,那么調用就會成功;如果可選值是 nil ,那么調用將返回 nil 。多個調用可以連接在一起形成一個調用 鏈,如果其中任何一個節(jié)點為 nil ,整個調用鏈都會失敗,即返回 nil 。
    
    //使用可選鏈式調用代替強制展開
    //通過在想調用的屬性、方法、或下標的可選值后面放一個問號( ? ),可以定義一個可選鏈。這一點很像在可選 值后面放一個嘆號( ! )來強制展開它的值。它們的主要區(qū)別在于當可選值為空時可選鏈式調用只會調用失 敗,然而強制展開將會觸發(fā)運行時錯誤。
    
    //下面幾段代碼將解釋可選鏈式調用和強制展開的不同
    class Person {
    
        var residence:Residence?
    
        
    }
    
    class Residence {
    
        var numberOfRooms = 1
        
    }
    //Residence 有一個 Int 類型的屬性 numberOfRooms ,其默認值為 1 。 Person 具有一個可選的 residence 屬 性,其類型為 Residence? 。
    //假如你創(chuàng)建了一個新的 Person 實例,它的 residence 屬性由于是是可選型而將初始化為 nil ,在下面的代碼中, jo hn 有一個值為 nil 的 residence 屬性:
    let john = Person()
    
    //如果使用嘆號( ! )強制展開獲得這個 john 的 residence 屬性中的 numberOfRooms 值,會觸發(fā)運行時錯誤,因為 這時 residence 沒有可以展開的值:
//        let roomCount = john.residence!.numberOfRooms // 這會引發(fā)運行時錯誤
    
    //可選鏈式調用提供了另一種訪問 numberOfRooms 的方式,使用問號( ? )來替代原來的嘆號( ! ):
    if let roomCount = john.residence?.numberOfRooms {
         print("John's residence has \(roomCount) room(s).")
    }else{
         print("Unable to retrieve the number of rooms.")
    }
    // 打印 “Unable to retrieve the number of rooms.”
    
    //在 residence 后面添加問號之后,Swift 就會在 residence 不為 nil 的情況下訪問 numberOfRooms 。
    
    //因為訪問 numberOfRooms 有可能失敗,可選鏈式調用會返回 Int? 類型,或稱為“可選的 Int ”。如上例所 示,當 residence 為 nil 的時候,可選的 Int 將會為 nil ,表明無法訪問 numberOfRooms 。訪問成功時,可選的Int 值會通過可選綁定展開,并賦值給非可選類型的 roomCount 常量。
   // 要注意的是,即使 numberOfRooms 是非可選的 Int 時,這一點也成立。只要使用可選鏈式調用就意味著numberOfRooms 會返回一個 Int? 而不是 Int 。
    //可以將一個 Residence 的實例賦給 john.residence ,這樣它就不再是 nil 了:
    john.residence = Residence()
    
    //john.residence 現(xiàn)在包含一個實際的 Residence 實例,而不再是 nil 。如果你試圖使用先前的可選鏈式調用訪問 numberOfRooms ,它現(xiàn)在將返回值為 1 的 Int? 類型的值:
    
    if let roomCount = john.residence?.numberOfRooms {
        print("John's residence has \(roomCount) room(s).")
    }else {
        print("Unable to retrieve the number of rooms.")
    }
    // 打印 “John's residence has 1 room(s).”
    
    
    //為可選鏈式調用定義模型類
    
    //通過使用可選鏈式調用可以調用多層屬性、方法和下標。這樣可以在復雜的模型中向下訪問各種子屬性,并且判斷能否訪問子屬性的屬性、方法或下標。
    //下面這段代碼定義了四個模型類,這些例子包括多層可選鏈式調用。為了方便說明,在 Person 和 Residence 的基 礎上增加了 Room 類和 Address 類,以及相關的屬性、方法以及下標。
    
    //Person1 類的定義基本保持不變:
    //  Residence 類比之前復雜些,增加了一個名為 rooms 的變量屬性,該屬性被初始化為 [Room] 類型的空數(shù)組:
    
    class Person1 {
        
        var residence:Residence1?
        
    }

    
    class Residence1 {
    
        var rooms:Array<Room>
        
        var numberOfRooms: NSInteger {
        
            return rooms.count
        }
      
        subscript(i:NSInteger) -> Room {
        
            get {
            return rooms[i]
            }
            set {
            
                rooms[i] = newValue
            }
        }
        func prinfNumberOfRooms() {
            print("The number of rooms is \(numberOfRooms)")
        }
        var address:Address?
        
        init(rooms:Array<Room> , address: Address?) {
            self.rooms = rooms
            self.address = address
        }
        
    }
    
    class Room {
    
        let name: String
        init(name: String) {
            self.name = name
        }
        
    }
    
    class Address {
    
        var buildingName:String?
        var buildingNumber:String?
        var street:String?
        func buildingIdentifier() -> String? {
            if buildingName != nil {
                return buildingName
            }else if buildingNumber != nil && street != nil {
            
                return "\(buildingNumber) \(street)"
            }else {
            
                return nil
            }
        }
    }
    
    
    //下面的代碼創(chuàng)建了一個 Person 實例,然后像之前一樣,嘗試訪問 numberOfRooms 屬性:
    //因為 john.residence 為 nil ,所以這個可選鏈式調用依舊會像先前一樣失敗。
    let john1 = Person1()
    if let roomCount = john1.residence?.numberOfRooms {
        print("John's residence has \(roomCount) room(s).")
    } else {
        print("Unable to retrieve the number of rooms.")
    }
    // 打印 “Unable to retrieve the number of rooms.”
    
   // 還可以通過可選鏈式調用來設置屬性值:
    
    let someAddress = Address()
    someAddress.buildingNumber = "29"
    someAddress.street = "Acacia Road"
    john1.residence?.address = someAddress
    
   // 在這個例子中,通過 john.residence 來設定 address 屬性也會失敗,因為 john.residence 當前為 nil 。
    
    
    func createAddress() -> Address {
        print("Function was called.")
        let someAddress = Address()
        someAddress.buildingNumber = "29"
        someAddress.street = "Acacia Road"
        return someAddress
    }
    john1.residence?.address = createAddress()
    
    //沒有任何打印消息,可以看出 createAddress() 函數(shù)并未被執(zhí)行。
    
    //通過可選鏈式子調用調用方法
    //func prinfNumberOfRooms() {
     //   print("The number of rooms is \(numberOfRooms)")
    //}
    
    //最后通過判斷調用
    if john1.residence?.prinfNumberOfRooms() != nil {
        print("It was possible to print the number of rooms.")
    } else {
        print("It was not possible to print the number of rooms.")
    }
    // 打印 “It was not possible to print the number of rooms.”
    //同樣的,可以據(jù)此判斷通過可選鏈式調用為屬性賦值是否成功
    
    if (john1.residence?.address = someAddress) != nil {
        print("It was possible to set the address.")
    } else {
        print("It was not possible to set the address.")
    }
    // 打印 “It was not possible to set the address.”
    
    
    //同樣的,可以據(jù)此判斷通過可選鏈式調用為屬性賦值是否成功。在上面的通過可選鏈式調用訪問屬性.我們嘗試給 john1.residence 中的 address 屬性賦值,即使 residence 為 nil 。通過可選鏈式調用給屬性賦 值會返回 Void? ,通過判斷返回值是否為 nil 就可以知道賦值是否成功:
    if let firstRoomName = john1.residence?[0].name {
        print("The first room name is \(firstRoomName).")
    } else {
        print("Unable to retrieve the first room name.")
    }
    // 打印 “Unable to retrieve the first room name.”
    
    //通過可選鏈式調用訪問下標
    if let firstRoomName = john1.residence?[0].name {
        print("The first room name is \(firstRoomName).")
    } else {
        print("Unable to retrieve the first room name.")
    }
    // 打印 “Unable to retrieve the first room name.”
    
    //如果創(chuàng)建一個Residence1實例,并為其rooms數(shù)組添加一些Room實例,然后將residence實例賦值給john.residence,那就可以通過可選鏈和下標來訪問數(shù)組
   // let johnsHouse = Residence1()
   // johnsHouse.rooms.append(Room(name: "Living Room"))
    //johnsHouse.rooms.append(Room(name: "Kitchen"))
    //john1.residence = johnsHouse
    //if let firstRoomName = john1.residence?[0].name {
     //   print("The first room name is \(firstRoomName).")
    //} else {
      //  print("Unable to retrieve the first room name.")
    //}
    // 打印 “The first room name is Living Room.”
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容