Ссылка на метод экземпляра требует эквивалентности (SWIFT) - PullRequest
0 голосов
/ 29 сентября 2019

Я пытаюсь использовать SwiftUI и Combine для хранения пользовательских настроек по умолчанию для моего приложения. Просматривая предложения в нескольких других постах, я обновил свой код, как вы видите ниже. Однако теперь я получаю сообщение об ошибке «Ссылка на метод экземпляра send () для Subject требует, чтобы типы« Setup »и« Void »были эквивалентны». Было предложено, чтобы я изменил «Setup» на void в PassthroughSubject, однако это затем приводит к серьезному сбою в приложении при запуске - «Неустранимая ошибка: Обнаруженный объект типа Setup.Type не найден».

Я в некоторой растерянности ... любые указатели будут приветствоваться.

    ==============  DataStoreClass ============

import SwiftUI
import Foundation
import Combine

class Setup: ObservableObject {

    private var notificationSubscription: AnyCancellable?

    let objectWillChange = PassthroughSubject<Setup,Never>()

    @UserDefault(key: "keyValueBool", defaultValue: false)
    var somevalueBool: Bool {
        didSet{
            objectWillChange.send()  // <====== Referencing instance method 'send()' on 'Subject' requires the types 'Setup' and 'Void' be equivalent
        }
    }
    init() {

        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
                   self.objectWillChange.send()
        }
    }
}


============= property wrapper ===========
import Foundation

@propertyWrapper
struct UserDefault<T> {
    let key: String
    let defaultValue: T

    var wrappedValue: T {
        get {
            UserDefaults(suiteName: "group.com.my.app")!.value(forKey: key) as? T ?? defaultValue
        } set {
            UserDefaults(suiteName: "group.com.my.app")!.set(newValue, forKey: key)
        }
    }
}

Ответы [ 3 ]

1 голос
/ 30 сентября 2019

Ошибка возникает из-за того, что вы объявили тип Output как Setup, но вы вызываете objectWillChange с Void.

Таким образом, вы должны передать self в objectWillChange:

self.objectWillChange.send(self)

Важно отметить, что вы должны вызывать objectWillChange не в didSet, а в willSet:

var somevalueBool: Bool {
    willSet{
        objectWillChange.send(self
    }
}

Вы никогда не установите somevalueBool, поэтому этот бит кода будетне вызывать в любом случае.

Ваша установка должна выглядеть примерно так:

class Setup: ObservableObject {

    private var notificationSubscription: AnyCancellable?

    public let objectWillChange = PassthroughSubject<Setup,Never>()

    @UserDefault(key: "keyValueBool", defaultValue: false)
    var somevalueBool: Bool

    init() {
        notificationSubscription = NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification).sink { _ in
                   self.objectWillChange.send(self)
        }
    }
}
0 голосов
/ 30 сентября 2019

SwiftUI не использует PassthroughSubject, он использует ObservableObjectPublisher. Я почти уверен, что это псевдоним для PassthroughSubject<Void, Never>, но я не уверен. Протокол ObservableObject определяет правильный objectWillChange для вас, поэтому лучшее, что вы можете сделать, это удалить свое определение.

Издатель - objectWillChange, и, как следует из его названия, его следует отправлять в willSet, а не didSet, я не думаю, что это имеет большое значение, но Apple изменила с didSet на willSet и я думаю, что у них была веская причина.

0 голосов
/ 30 сентября 2019

Метод send требует, чтобы вы передали тип ввода субъекта или завершение ошибки. Таким образом, ваши send строки должны проходить Setup;

objectWillChange.send(self)

Тем не менее, в большинстве кодов SwiftUI PassthroughSubject равно <Void, Never> (так что send() не требует параметра). Непонятно, какой источник аварии вы описываете;нам нужно увидеть код, который участвует в сбое, чтобы отладить это. Я до сих пор не воспроизвел это.

...