Rangkaian pilihan pantas


Perangkaian Pilihan ialah proses yang boleh meminta dan memanggil sifat, kaedah dan subskrip Sasaran untuk meminta atau membuat panggilan mungkin tiada.

Rantai pilihan mengembalikan dua nilai:

  • Jika sasaran mempunyai nilai, panggilan akan berjaya dan mengembalikan nilai tersebut

  • Jika sasaran adalah sifar, panggilan akan kembali sifar

Berbilang permintaan atau panggilan boleh dipautkan ke dalam rantaian Jika mana-mana nod sifar, keseluruhan rantai akan gagal.


Perantaian pilihan boleh menggantikan penghuraian paksa

Pilihan boleh ditakrifkan dengan meletakkan tanda soal (?) selepas nilai pilihan bagi harta, kaedah atau rantaian skrip subskrip.

可选链 '?'感叹号(!)强制展开方法,属性,下标脚本可选链
? 放置于可选值后来调用方法,属性,下标脚本! 放置于可选值后来调用方法,属性,下标脚本来强制展开值
当可选为 nil 输出比较友好的错误信息当可选为 nil 时强制展开执行错误

Gunakan tanda seru (!) contoh rantai pilihan

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

//将导致运行时错误
let roomCount = john.residence!.numberOfRooms

Hasil output pelaksanaan program di atas ialah:

fatal error: unexpectedly found nil while unwrapping an Optional value


Saya ingin menggunakan tanda seru (!) untuk paksa parsing untuk mendapatkan orang ini Nilai atribut residence attribute numberOfRooms akan menyebabkan ralat masa jalan kerana tiada nilai kediaman yang boleh dihuraikan pada masa ini.


Gunakan tanda seru (!) contoh rantai pilihan

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

// 链接可选residence?属性,如果residence存在则取回numberOfRooms的值
if let roomCount = john.residence?.numberOfRooms {
    print("John 的房间号为 \(roomCount)。")
} else {
    print("不能查看房间号")
}

Hasil output pelaksanaan program di atas ialah:

不能查看房间号

Disebabkan oleh operasi ini cuba mendapatkan numberOfRooms Jika gagal, rantai pilihan akan mengembalikan nilai jenis Int?, juga dikenali sebagai "Int pilihan". Apabila kediaman kosong (contoh di atas), Int yang dipilih akan kosong, jadi numberOfRooms tidak akan dapat diakses.

Perhatikan bahawa ini berlaku walaupun numberOfRooms ialah Int bukan pilihan (Int?). Selagi permintaan itu melalui rangkaian pilihan, ini bermakna numberOfRooms terakhir sentiasa mengembalikan Int dan bukannya Int.


Tentukan kelas model untuk rantai pilihan

Anda boleh menggunakan rantai pilihan untuk memanggil sifat, kaedah dan skrip subskrip pada berbilang peringkat. Ini membolehkan anda memanfaatkan model kompleks di antara mereka untuk mendapatkan sifat peringkat rendah dan menyemak sama ada anda boleh berjaya mendapatkan sifat peringkat rendah tersebut.

Instance

mentakrifkan empat kelas model, yang termasuk berbilang lapisan rantai pilihan:

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

Kaedah panggilan melalui rantai pilihan

Anda boleh menggunakan rantaian pilihan untuk memanggil kaedah pada nilai pilihan dan semak sama ada panggilan kaedah berjaya. Walaupun kaedah ini tidak mengembalikan nilai, anda masih boleh menggunakan rantaian pilihan untuk tujuan ini.

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()


if ((john.residence?.printNumberOfRooms()) != nil) {
    print("输出房间号")
} else {
    print("无法输出房间号")
}

Output pelaksanaan program di atas ialah:

无法输出房间号

Gunakan pernyataan if untuk menyemak sama ada kaedah printNumberOfRooms boleh berjaya dipanggil: Jika kaedah itu berjaya dipanggil melalui rantai pilihan, nilai pulangan tersirat printNumberOfRooms akan menjadi Is Void, jika tidak berjaya, tiada akan dikembalikan.


Menggunakan rantaian pilihan untuk memanggil skrip subskrip

Anda boleh menggunakan rantaian pilihan untuk cuba mendapatkan nilai daripada skrip subskrip dan semak sama ada panggilan ke skrip subskrip berjaya, walau bagaimanapun, skrip Subskrip anda tidak boleh ditetapkan melalui rantaian pilihan.

Contoh 1

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()
if let firstRoomName = john.residence?[0].name {
    print("第一个房间名 \(firstRoomName).")
} else {
    print("无法检索到房间")
}

Hasil output pelaksanaan program di atas ialah:

无法检索到房间

Tanda soal rantai pilihan dalam panggilan skrip subskrip terus mengikuti circname.print, dalam subskrip sebelum kurungan skrip, kerana circname.print ialah nilai pilihan yang cuba diperolehi oleh rantai pilihan.

Instance 2

Buat instance Residence untuk john.residence, dan terdapat satu atau lebih tika Room dalam susunan biliknya, kemudian anda boleh menggunakan rantai pilihan untuk memuat turunnya melalui skrip Residence Subscript untuk mendapatkan contoh dalam tatasusunan bilik:

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()
let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("第一个房间名为\(firstRoomName)")
} else {
    print("无法检索到房间")
}

Hasil output pelaksanaan program di atas ialah:

第一个房间名为客厅

Akses subskrip

<🎜 melalui pautan pilihan panggilan >Melalui panggilan pautan pilihan, kami boleh menggunakan subskrip untuk membaca atau menulis nilai pilihan, dan menentukan sama ada panggilan subskrip berjaya.

Contoh

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("第一个房间名为\(firstRoomName)")
} else {
    print("无法检索到房间")
}

Hasil output pelaksanaan program di atas ialah:

第一个房间名为客厅


Mengakses subskrip jenis pilihan

Jika subskrip dikembalikan, ia boleh menjadi nilai Jenis nol, seperti subskrip utama Kamus dalam Swift. Anda boleh memautkan nilai pulangan nullable subskrip dengan meletakkan tanda soal selepas kurungan penutup subskrip:

var testScores = ["Dave": [86, 82, 84], "Bev": [79, 94, 81]]
testScores["Dave"]?[0] = 91
testScores["Bev"]?[0]++
testScores["Brian"]?[0] = 72
// the "Dave" array is now [91, 82, 84] and the "Bev" array is now [80, 94, 81]

Contoh di atas mentakrifkan tatasusunan testScores, yang mengandungi dua pasangan nilai kunci dan memetakan kekunci jenis Rentetan kepada tatasusunan integer.

Contoh ini menggunakan panggilan rantai pilihan untuk menetapkan elemen pertama dalam tatasusunan "Dave" kepada 91, +1 elemen pertama dalam tatasusunan "Bev", dan kemudian cuba untuk menetapkan elemen pertama dalam "Brian " tatasusunan Satu elemen ditetapkan kepada 72.

Dua panggilan pertama berjaya kerana dua kekunci ini wujud. Tetapi kunci "Brian" tidak wujud dalam kamus, jadi panggilan ketiga gagal.


Sambungkan pautan berbilang lapisan

Anda boleh menyambung rantai pilihan berbilang lapisan bersama-sama dan anda boleh melombong kaedah atribut peringkat rendah dan skrip subskrip dalam model. Walau bagaimanapun, rantai pilihan berbilang peringkat tidak boleh menambah lebih banyak tahap daripada nilai pilihan yang telah dikembalikan.

Jika anda cuba mendapatkan nilai Int melalui rantaian pilihan, tidak kira berapa tahap rantaian digunakan, hasilnya akan sentiasa Int?. Begitu juga, jika anda cuba mendapatkan nilai Int melalui rantaian pilihan, hasilnya akan sentiasa menjadi Int?, tidak kira berapa tahap rantaian digunakan.

Contoh 1

Contoh berikut cuba mendapatkan atribut jalanan alamat dalam atribut kediaman john. Dua lapisan rantai pilihan digunakan di sini untuk menyambungkan sifat kediaman dan alamat, kedua-duanya adalah jenis pilihan:

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()

if let johnsStreet = john.residence?.address?.street {
    print("John 的地址为 \(johnsStreet).")
} else {
    print("不能检索地址")
}

Hasil output pelaksanaan program di atas ialah:

不能检索地址

Contoh 2

Jika anda menetapkan contoh Alamat sebagai nilai john.residence.address, dan menetapkan nilai sebenar untuk atribut jalan alamat, anda boleh mendapatkan nilai atribut ini melalui berbilang rantai pilihan.

class Person {
   var residence: Residence?
}

class Residence {
    
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        get{
            return rooms[i]
        }
        set {
            rooms[i] = newValue
        }
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var 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) {
            return buildingNumber
        } else {
            return nil
        }
    }
}
let john = Person()
john.residence?[0] = Room(name: "浴室")

let johnsHouse = Residence()
johnsHouse.rooms.append(Room(name: "客厅"))
johnsHouse.rooms.append(Room(name: "厨房"))
john.residence = johnsHouse

if let firstRoomName = john.residence?[0].name {
    print("第一个房间是\(firstRoomName)")
} else {
    print("无法检索房间")
}

Hasil keluaran contoh di atas ialah:

第一个房间是客厅

Fungsi pautan yang mengembalikan nilai pilihan

Kita juga boleh memanggil nilai nullable pulangan melalui nilai pautan pilihan , dan boleh terus merantai nilai pilihan.

Contoh

class Person {
    var residence: Residence?
}

// 定义了一个变量 rooms,它被初始化为一个Room[]类型的空数组
class Residence {
    var rooms = [Room]()
    var numberOfRooms: Int {
        return rooms.count
    }
    subscript(i: Int) -> Room {
        return rooms[i]
    }
    func printNumberOfRooms() {
        print("房间号为 \(numberOfRooms)")
    }
    var address: Address?
}

// Room 定义一个name属性和一个设定room名的初始化器
class Room {
    let name: String
    init(name: String) { self.name = name }
}

// 模型中的最终类叫做Address
class Address {
    var buildingName: String?
    var buildingNumber: String?
    var street: String?
    func buildingIdentifier() -> String? {
        if (buildingName != nil) {
            return buildingName
        } else if (buildingNumber != nil) {
            return buildingNumber
        } else {
            return nil
        }
    }
}

let john = Person()

if john.residence?.printNumberOfRooms() != nil {
    print("指定了房间号)")
}  else {
    print("未指定房间号")
}

Hasil output pelaksanaan program di atas ialah:

未指定房间号