类函数的初始化成员导致方法调用错误中使用“自我”

Fel*_*ler 9 initialization class function ios swift

我有一个指向类功能之一的类属性。但是,当我尝试使用函数之一初始化此变量时,出现以下错误:

在初始化所有存储的属性之前,在方法调用中使用“ self”。

我可以为这些函数初始化任何其他变量,但是即使没有,该错误也听起来像我在调用该函数。

import UIKit
import AudioToolbox

class BeatMaker {

    // iPhone 7 and up use beat function, iPhone 6s use beatFallback
    let hapticFunction: () -> ()
    let impactGenerator = UIImpactFeedbackGenerator.init(style: .heavy)

    init(supportsImpactGenerator: Bool) {
        // error 1: 'self' used in method call 'beat' before all stored properties are initialized
        // error 2: 'self' used in method call 'beatFallback' before all stored properties are initialized
        self.hapticFunction = (supportsImpactGenerator) ? beat : beatFallback
    }

    private func beat() {
        impactGenerator.impactOccurred()
    }

    private func beatFallback() {
        AudioServicesPlaySystemSound(1520)
    }

    func makeABeat() {
        hapticFunction()
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,我想使用Taptic Engine并模拟通过点击UIImpactFeedbackGenerator。iPhone 6s不支持该引擎,因此我想调用产生类似效果的后备功能。

我还尝试当场初始化变量:

// this works
var hapticFunction: (BeatMaker) -> () -> () = beat

init(supportsImpactGenerator: Bool) {
    if !supportsImpactGenerator {
        // error: Cannot assign value of type '() -> ()' to type '(BeatMaker) -> () -> ()'
        self.hapticFunction = beatFallback

        // produces same error
        self.hapticFunction = beatFallback.self
    }
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以使所有内容静态化或将所有内容排除在课堂之外,但这听起来像应该可以,但不能。我想念什么吗?

编辑

将type的类型设置为hapticFunction可选似乎可行,但这对我来说没有任何意义。有什么不同?

// this works
var hapticFunction: (() -> ())?

init(supportsImpactGenerator: Bool) {
    self.hapticFunction = (supportsImpactGenerator) ? beat : beatFallback
}
Run Code Online (Sandbox Code Playgroud)

Saj*_*jon 4

最好不要使用 a Bool,而使用嵌套的Enum,如果您想稍后添加一些其他触觉反馈模式,它也更具可扩展性。

我对你的问题的普遍问题有一个普遍的解决方案。所以你要么这样做:


public class FunctionOwner {

    private let mode: Mode

    public init(`do` mode: Mode = .default) {
        self.mode = mode
    }
}


public extension FunctionOwner {

    enum Mode {
        case foo, bar
    }

    func fooOrBar() {
        switch mode {
        case .foo: foo()
        case .bar: bar()
        }
    }
}

private extension FunctionOwner {
    func foo() {
        print("doing foo")
    }

    func bar() {
        print("doing bar")
    }
}

public extension FunctionOwner.Mode {
    static var `default`: FunctionOwner.Mode {
        return .foo
    }
}

// USAGE
FunctionOwner(do: .bar).fooOrBar() // prints "doing foo"
FunctionOwner(do: .foo).fooOrBar() // prints "doing bar"

Run Code Online (Sandbox Code Playgroud)

或者,如果您出于某种原因确实想要保留 Stored Mode,您可以这样做(可能与您关于如何self在 init 中进行引用的解决方法的实际问题相关):

public class FunctionOwner {

    private let _function: (FunctionOwner) -> Void

    public init(`do` mode: Mode = .default) {
        _function = { functionOwner in
            switch mode {
            case .foo: functionOwner.foo()
            case .bar: functionOwner.bar()
            }
        }
    }
}

public extension FunctionOwner {

    enum Mode {
        case foo, bar
    }

    func fooOrBar() {
        _function(self)
    }
}

// The rest of the code is the same as the example above
Run Code Online (Sandbox Code Playgroud)