如何正确初始化init()引发的非局部不可变?

时间:2019-01-25 01:20:09

标签: swift initialization immutability optional

考虑这些事实:

1)最好将对象初始化为let(不可变),而不是var。

2)某些对象在调用其初始化程序时会抛出(例如,AVAudioPlayer,例如 )。

3)某些对象的初始化程序要求的参数在“自我可用”之前是不可用的,例如AVAudioPlayer,因此,如果它们将成为类级/非本地let,则必须将其初始化不在之前或之后,而仅在init()内部。

例如,假设我们有一个类,我们要定义一个AVAudioPlayer类型的类级属性(或其他任何其init方法引发的对象),但我们希望它是一个let。

经过反复试验,围绕X代码警告进行协商,并尝试了可选选项,我在(带有帮助的情况下)提出的最好的建议是:

import AVFoundation

class MySoundPoolPlayer {

    private let dingURL = Bundle.main.url(forResource: "ding", withExtension: "wav")
    private let dongURL = Bundle.main.url(forResource: "dong", withExtension: "wav")

    private let dingPlayer: AVAudioPlayer?
    private let dongPlayer: AVAudioPlayer?

    init() {

        dingPlayer = try? AVAudioPlayer(contentsOf: dingURL!)
        dongPlayer = try? AVAudioPlayer(contentsOf: dongURL!)

    }

    func playDing() {
        dingPlayer!.play()
    }

    func playDong() {
        dongPlayer!.play()
    }

    func stopAllSounds() {
        dingPlayer!.stop()
        dongPlayer!.stop()
    }

}

因此,现在基本上我们有了一个不可变的值,如果AVAudioPlayer.init()抛出,则该值可能为零...但是至少它是一个让,并且由于将其设置为可选值,因此如果该应用程序不会崩溃AVAudioPlayer.init()抛出。

有更好的方法吗?

初始化这些类型的对象(作为类级别)的最佳实践是什么?

非常感谢您的时间和考虑! XD

1 个答案:

答案 0 :(得分:1)

基本上,您有三个选择:

  1. 强制尝试(try!),如果您100%确信AVAudioPlayer将成功。但是请注意,即使该网址包含有效内容,初始化器仍可能由于其他内部条件而失败
  2. 将属性标记为可选属性(就像您所做的那样),这将防止出现故障,但是会增加其余代码的复杂性,因为您需要始终解开属性。
  3. 将您的初始化程序标记为throwing。这将把处理错误的负担移到上游,但是在某些时候,您可能仍需要使用#1 /#2方法。

以上所有解决方案在某处都需要妥协,因为您迟早需要处理初始化失败。问题是您要如何执行此操作:

  • 由于AVAudioPlayer故障无法在您的应用中恢复,导致应用崩溃
  • 处理初始化失败并通过应用程序提供另一条路径
  • 静静地忽略故障,并继续使用该应用程序

这一切都取决于您的应用程序的细节。