.send() и.sink(), похоже, больше не работают для PassthroughSubject в Xcode 11 Beta 5

В следующем коде "Тест" должен быть напечатан в консоли при нажатии кнопки, но это не так. Событие не отправлено через издателя. Есть идеи, что случилось с PassthroughSubject в Xcode 11 Beta 5? (в Xcode 11 Beta 4 это работает хорошо)

var body: some View {  

    let publisher = PassthroughSubject<String, Never>()

    publisher.sink { (str) in  
        print(str)  
    }  
    return Button("OK") {  
        publisher.send("Test")  
    }  
}

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

1 ответ

Решение

.sink() возвращает AnyCancellable объект. Вы никогда не должны игнорировать это. Никогда не делай этого:

// never do this!
publisher.sink { ... }
// never do this!
let _ = publisher.sink { ... }

И если вы присваиваете его переменной, убедитесь, что она недолговечна. Как только отменяемый объект будет освобожден, подписка также будет отменена.

// if cancellable is deallocated, the subscription will get cancelled
let cancellable = publisher.sink { ... }

Так как вы попросили использовать sink внутри представления я опубликую способ сделать это. Тем не менее, в представлении, вы, вероятно, должны использовать .onReceive() вместо. Это намного проще.

Используя раковину:

При использовании его внутри представления вам необходимо использовать @State переменная, чтобы убедиться, что он выживает после генерации тела представления.

DispatchQueue.main.async требуется, чтобы избежать изменения состояния при обновлении представления. Вы получите ошибку во время выполнения, если вы этого не сделали.

struct ContentView: View {
    @State var cancellable: AnyCancellable? = nil

    var body: some View {
        let publisher = PassthroughSubject<String, Never>()

        DispatchQueue.main.async {
            self.cancellable = publisher.sink { (str) in
                print(str)
            }
        }

        return Button("OK") {
            publisher.send("Test")
        }
    }
}

С помощью.onReceive()

struct ContentView: View {

    var body: some View {
        let publisher = PassthroughSubject<String, Never>()

        return Button("OK") {
            publisher.send("Test")
        }
        .onReceive(publisher) { str in
            print(str)
        }
    }
}

При подписке на раковину вам не хватает.store. Вы можете использовать.onReceive, но ваш код не получает значений, потому что вам нужно добавить.store(в: &subscription)

var body: some View {  
    var subscription = Set<AnyCancellable>()
    let publisher = PassthroughSubject<String, Never>()

    publisher.sink { (str) in  
        print(str)  
    }.store(in: &subscription)

    return Button("OK") {  
        publisher.send("Test")  
    }  
}
Другие вопросы по тегам