创建AVAudioPlayers时了解Swift中的Optionals

时间:2018-08-03 14:20:39

标签: ios swift optional

我是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?.delegateplayer?.prepareToPlay() < / p>

对不起,三个问题,但相互关联……

答案确实会帮助我掌握Swift的这一基本方面。

3 个答案:

答案 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。如果playernil,则该行的其余部分将被忽略。


由于音频文件必须存在,因为应用程序捆绑包在运行时不可更改,因此可以省略所有guardcatch。该代码不得崩溃。如果是,您犯了设计错误。

var player = AVAudioPlayer()

let audioURL = Bundle.main.url(forResource: "sample-audio", withExtension: "caf")!
player = try! AVAudioPlayer(contentsOf: audioURL)
player.prepareToPlay()