我是Swift的新手,从Obj-C过渡过来,对其他语言没有太多经验。
我已经阅读了有关可选的内容,了解了总体前提,并了解了为什么它们可能是一件好事。但是我正在努力地掌握它们在实践中的工作方式。以下代码可以正常工作,但是我想解释一下为什么这样。
我正在开发一个使用AVAudioPlayer
播放文件音频的应用。我首先创建AVAudioPlayer类的实例:
var player: AVAudioPlayer?
Q1。为什么这必须是可选类型?大概是因为尚未初始化/尚未包含任何数据?
我随后用于将音频加载到player
中的代码如下:
guard let audioFile = Bundle.main.path(forResource: "sample-audio", ofType: "caf") else {
print("sample-audio.caf does not exist in the bundle.")
return
}
let audioURL = URL(fileURLWithPath: audioFile)
do {
player = try AVAudioPlayer(contentsOf: audioURL)
player?.delegate = self
player?.prepareToPlay()
} catch {
print(error)
}
Q2。如果player
是可选类型,为什么在使用try / catch语句为其分配URL时在这里省略?
符号?
Q3。如果一个可选值就像一个“您必须打开的框”,其中包含一个值或不包含任何值/无,那么如何直接调用其上的属性和函数,例如player?.delegate
和player?.prepareToPlay()
< / p>
对不起,三个问题,但相互关联……
答案确实会帮助我掌握Swift的这一基本方面。
答案 0 :(得分:1)
Q1:它不一定是可选的,但是是的,它当时还没有初始化。您有几种选择:?
并在需要时对其进行初始化,!
并且必须先对其进行初始化,然后再尝试使用它,否则程序将崩溃,或者在声明时进行初始化。您所做的完全取决于上下文。在这种情况下,最好将其设置为可选。
第二季度:在该行上不需要?
。它会去哪里?编译器知道player
是可选的,没有任何东西被解包,您只是在为可选变量分配一个值。
Q3:Optional chaining允许您调用可选对象上的内容,而无需先实际对其进行包装。它只是隐式地为您工作,因此您的代码可以更加简洁。如果对象为nil,则什么都不会发生,否则它将运行该调用。请注意,它会级联降低可选性,因此即使属性etc不是可选的,它也会在这样的语句中继承可选性。
答案 1 :(得分:0)
do-catch
流程始终与可选流程有关,假设您这样声明播放器
var player: AVAudioPlayer!
并且do块失败,这可能是VC使用播放器的其他部分,因此一旦被引用,该应用将由于!而崩溃,这就是为什么它被声明为?
//
是什么在这里
player?.delegate = self
如果player为nil,则该语句将不会运行,否则,将设置委托
//
你不这样做
player? = //////
因为它没有意义,将导致该语句无法运行,因为它的关键是调用播放器的属性和方法(如果不为nil,并且此处没有附加或调用的内容)
答案 2 :(得分:0)
A1:是,因为它尚未初始化/尚未包含任何数据。但是在这种情况下-该属性将始终在使用之前初始化-您可以将其声明为隐式未包装的可选AVAudioPlayer!
并摆脱问号。在这种特殊情况下,您甚至可以将非可选参数与默认初始化程序AVAudioPlayer
一起使用,但这不适用于任何类型。
var player = AVAudioPlayer()
A2:您可以将非可选值和可选值都分配给可选变量。 ?
仅在您从变量发送消息时才有意义。
A3:player?.delegate = self
被称为Optional chaining
。如果player
为nil
,则该行的其余部分将被忽略。
由于音频文件必须存在,因为应用程序捆绑包在运行时不可更改,因此可以省略所有guard
和catch
。该代码不得崩溃。如果是,您犯了设计错误。
var player = AVAudioPlayer()
let audioURL = Bundle.main.url(forResource: "sample-audio", withExtension: "caf")!
player = try! AVAudioPlayer(contentsOf: audioURL)
player.prepareToPlay()