可选的链接和绑定

时间:2014-06-16 13:09:31

标签: swift

当我分配变量ammo(和ammo2)时,在可选绑定内部我很确定我应该使用!来取消选中可选项,但是在我第一次尝试时我错误地放了?并且有点困惑,为什么它仍然有效,是否有人可以在那里投射一些光线?

let soldierA = Soldier(name: "Brian")
soldierA.weapon = Weapon()
soldierA.weapon!.grenadeLauncher = GrenadeLauncher()

let soldierB = Soldier(name: "Gavin")
soldierB.weapon = Weapon()

let soldierC = Soldier(name: "Berty")
soldierC.weapon = Weapon()
soldierC.weapon!.grenadeLauncher = GrenadeLauncher()
soldierC.weapon!.grenadeLauncher!.ammo = 234

let missionTeam = [soldierA, soldierB, soldierC]
for eachSoldier in missionTeam {
    if let launcherAvailable = eachSoldier.weapon?.grenadeLauncher? {
        var ammo =  eachSoldier.weapon!.grenadeLauncher!.ammo // PRETTY SURE THIS IS RIGHT
        var ammo2 = eachSoldier.weapon?.grenadeLauncher?.ammo // SHOULD THIS WORK, IT DOES?
        println("SOLDIER: \(eachSoldier.name), Weapon has launcher AMMO: \(ammo)")
    } else {
        println("SOLDIER: \(eachSoldier.name), Weapon does not have launcher ")
    }
}

// CLASSES
class Soldier {
    var name: String
    var weapon: Weapon?
    init(name: String) {
        self.name = name
    }
}

class Weapon {
    var ammo = 500
    var grenadeLauncher: GrenadeLauncher?
}

class GrenadeLauncher {
    var ammo = 20
}

修改

谢谢,我对这是如何工作感到困惑,但我现在看到发生了什么。这是修改后的eachSoldier部分,使用可选绑定和可选链接...

for eachSoldier in missionTeam {
    if let weapon = eachSoldier.weapon? {
        if let launcher = eachSoldier.weapon?.grenadeLauncher? {
            println("SOLDIER: \(eachSoldier.name) Weapon has launcher with \(launcher.ammo) ammo")
        } else {
            println("SOLDIER: \(eachSoldier.name) Weapon does not have launcher ")
        }
    } else {
        println("SOLDIER: \(eachSoldier.name) does not have weapon ")
    }
}

2 个答案:

答案 0 :(得分:3)

soldierC.weapon = Weapon()
soldierC.weapon!.grenadeLauncher = GrenadeLauncher()
soldierC.weapon!.grenadeLauncher!.ammo = 234

在当前模式中是正确的。


var ammo =  eachSoldier.weapon!.grenadeLauncher!.ammo

隐式展开weapon及其grenadeLauncher; 它不关心它们是否在之前被引入,因此如果您的代码在其中任何一个仍然是nil值时尝试解包,它可能会导致直接崩溃。


var ammo2 = eachSoldier.weapon?.grenadeLauncher?.ammo

尝试访问weapon及其grenadeLauncher; 如果该对象不存在,它们将被单独放置,因此没有任何反应,但ammo2仅为nil,应用程序可以继续。

因此你的流程可能类似于:

for eachSoldier in missionTeam {
    var ammo2 = eachSoldier.weapon?.grenadeLauncher?.ammo
    if ammo2 != nil {
        println("SOLDIER: \(eachSoldier.name), Weapon has launcher AMMO: \(ammo2)")
    } else {
        println("SOLDIER: \(eachSoldier.name), Weapon does not have launcher ")
    }
}

答案 1 :(得分:0)

除了@holex所说的内容之外,我还想说你的案例为Optional Chaining,如果你在可选项上使用?代替!变量(或常量),这意味着如果变量(或常量)不是nil,则检查。换句话说,它有一个价值。

关于可选链接的可爱之处在于您可以将其应用于多个级别。 例如:

让我们说你有这两个类:

class Student{
    var subjects: [Subject]?
}
class Subject{
    var name: String?
}

你创建了一个变量:

var william = Student()

您可以随时打印第一个主题的名称:

print(william.subjects?[0].name)

注意该print语句的结果是 nil ,而如果你这样解开它:

print(william.subjects![0].name)

您会收到运行时错误