Ошибка «Дополнительный аргумент» при использовании CombineLatest из фреймворка Combine - PullRequest
0 голосов
/ 19 февраля 2020

Эту проблему можно увидеть на следующей игровой площадке. Существует четыре опубликованных значения, которые будут обновляться асинхронно (изображение и три строки). Когда все четыре из них будут инициализированы или впоследствии изменены, пользовательский интерфейс необходимо будет обновить. Когда я пытаюсь перехватить этот поток данных с помощью CombineLatest4, компилятор немедленно возражает против четвертого аргумента с сообщением Extra argument in call. ( Примечание: следующий код на самом деле ничего не делает, так как у него есть только издатель, но достаточно выдать сообщение об ошибке в Playground).

import Combine
import UIKit

struct CustomerUpdates
{
    @Published var photo: UIImage!
    @Published var firstName: String!
    @Published var lastName: String!
    @Published var id: String!

    typealias customerTuple =
        (   photo: UIImage,
            firstName: String,
            lastName: String,
            id: String )
    var validatedCustomer: AnyPublisher< customerTuple, Never >
    {
        return Publishers.CombineLatest4( $photo,
                                          $firstName,
                                          $lastName,
                                          $id )
        {
            photo, firstName, lastName, id in
            if      photo == nil
                ||  firstName == nil
                ||  lastName == nil
                ||  id == nil
            {
                return nil
            }
            return ( photo!, firstName!, lastName!, id! )
        }
        .compactMap
        .return( on: RunLoop.main )
    }
}

Мой вопрос почему компилятор помечает четвертый аргумент ("id")? Документация Apple для структуры CombineLatest4 generi c гласит:

Издатель, который получает и объединяет последние элементы от четырех издателей.

Ответы [ 2 ]

2 голосов
/ 20 февраля 2020

Тип CombineLatest (и его более крупные варианты, включая CombineLatest4) не требуют закрытия преобразования. Но Publisher имеет combineLatest операторов , которые делают. Так что вы можете сказать это, если хотите:

    return $photo.combineLatest($firstName, $lastName, $id) {
        guard
            let photo = $0,
            let firstName = $1,
            let lastName = $2,
            let id = $3
            else { return nil }
        return ($0, $1, $2, $3)
    }
    .compactMap { $0 }
    .receive(on: RunLoop.main)
2 голосов
/ 19 февраля 2020

Проблема в том, что CombineLatest не принимает замыкание, оно просто испускает последнее значение, испускаемое всеми его восходящими потоками всякий раз, когда какой-либо из восходящих потоков испускает новое значение. Вместо этого ваше закрытие должно быть передано compactMap, то есть оператору, который принимает закрытие, возвращающее Optional, и выдает значение ниже по потоку, если возвращаемое значение не было nil.

struct CustomerUpdates {
    @Published var photo: UIImage!
    @Published var firstName: String!
    @Published var lastName: String!
    @Published var id: String!

    typealias CustomerTuple = (photo: UIImage, firstName: String, lastName: String, id: String)
    var validatedCustomer: AnyPublisher<CustomerTuple, Never> {

        return Publishers.CombineLatest4($photo, $firstName, $lastName, $id)
            .compactMap { photo, firstName, lastName, id in
                guard let photo = photo, let firstName = firstName, let lastName = lastName, let id = id else { return nil }
                return ( photo, firstName, lastName, id)
            }
        .receive(on: DispatchQueue.main)
        .eraseToAnyPublisher()
    }
}

A пара других вопросов, не связанных с вашим вопросом: такого оператора return(on:) нет, вам нужно receive(on:) и вы хотите передать DispatchQueue.main, а не RunLoop.main, чтобы иметь возможность публиковать sh обновления прямо в вашем пользовательском интерфейсе.

Имена типов должны быть UpperCamelCase в Swift, поэтому используйте CustomerTuple вместо customerTuple.

Кроме того, ваши свойства должны быть Optional (var photo: UIImage?), а не неявно развернуты необязательно ( var photo: UIImage!).

...