Инициализация члена функции класса приводит к тому, что self используется в ошибке вызова метода - PullRequest
9 голосов
/ 03 апреля 2019

У меня есть атрибут класса, который указывает на одну из функций класса. Однако, когда я пытаюсь инициализировать эту переменную с помощью одной из функций, я получаю следующую ошибку:

'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()
    }
}

В этом конкретном случае я хочу использовать 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
    }
}

Я знаю, что я мог бы сделать все статичным или исключить все из класса, но это чувствует, что должно работать, но это не так. Я что-то упустил?

EDIT

Установка типа типа hapticFunction на необязательное значение работает, но для меня это не имеет никакого смысла. Какая разница?

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

init(supportsImpactGenerator: Bool) {
    self.hapticFunction = (supportsImpactGenerator) ? beat : beatFallback
}

Ответы [ 2 ]

4 голосов
/ 03 апреля 2019

Может быть лучше не использовать 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"

, либо, если по какой-то причине вы хотите сохранить сохраненные значения Mode, вы можете сделать это (может иметь отношение к вашему актуальному вопросу о том, как вы можете обойти ссылкиself в иници.):

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
0 голосов
/ 03 апреля 2019

Есть два способа исправить это

Вы можете:

Дайте hapticFunction начальное значение как {}

или исправить как:

class BeatMaker {

    let impactGenerator = UIImpactFeedbackGenerator.init(style: .heavy)
    let supportsImpactGenerator: Bool

    init(supportsImpactGenerator: Bool) {
        self.supportsImpactGenerator = supportsImpactGenerator
    }

    private func beat() {
        if supportsImpactGenerator {
            impactGenerator.impactOccurred()
        } else {
            AudioServicesPlaySystemSound(1520)
        }
    }

    func makeABeat() {
        beat()
    }
}
...