Использование оператора zip в RxSwift после создания массива наблюдаемых

У меня есть объект newBid, который содержит массив данных и изображений. Я хочу загрузить все изображения и данные на сервер и zip эти загружаемые наблюдаемые объекты. Если я создам отдельные drivers для data, image1 и image2, у меня все получится.

Но что я действительно хочу сделать, так это не жестко кодировать изображения, поскольку массив может содержать от 0 до 10 изображений. Я хочу программно создать массив наблюдаемых и zip их.

let dataSaved = saveTaps.withLatestFrom(newBid)
    .flatMapLatest { bid in
        return CustomerManager.shared.bidCreate(bid: bid)
            .trackActivity(activityIndicator)
            .asDriver(onErrorJustReturn: false)
}

let photoSaved0 = saveTaps.withLatestFrom(newBid)
    .flatMapLatest { bid in
        return CustomerManager.shared.bidUploadFile(image: bid.images[0])
            .trackActivity(activityIndicator)
            .asDriver(onErrorJustReturn: false)
}

let photoSaved1 = saveTaps.withLatestFrom(newBid)
    .flatMapLatest { bid in
        return CustomerManager.shared.bidUploadFile(image: bid.images[1])
            .trackActivity(activityIndicator)
            .asDriver(onErrorJustReturn: false)
}

saveCompleted = Driver.zip(dataSaved, photoSaved0, photoSaved1){ return $0 && $1 && $2 }

/*
// 0. Getting array of images from newBid
let images = newBid.map { bid in
    return bid.images
}

// 1. Creating array of upload drivers from array of images
let imageUploads = images.map { (images: [UIImage]) -> [Driver<Bool>] in
    var temp = [Driver<Bool>]()
    return temp
}

// 2. Zipping array of upload drivers to photoSaved driver
photoSaved = Driver
    .zip(imageUploads) // wait for all image requests to finish
    .subscribe(onNext: { results in
        // here you have every single image in the 'images' array
        results.forEach { print($0) }
    })
    .disposed(by: disposeBag)*/

В разделе комментариев, если я попытаюсь zip загрузить изображение, я получаю сообщение об ошибке:

Argument type 'SharedSequence<DriverSharingStrategy, [SharedSequence<DriverSharingStrategy, Bool>]>' does not conform to expected type 'Collection'

person Denis Kutlubaev    schedule 16.08.2018    source источник


Ответы (2)


Как насчет чего-то подобного?

let saves = saveTaps.withLatestFrom(newBid)
    .flatMapLatest { (bid: Bid) -> Observable<[Bool]> in
        let dataSaved = CustomerManager.shared.bidCreate(bid: bid)
            .catchErrorJustReturn(false)

        let photosSaved = bid.images.map {
            CustomerManager.shared.bidUploadFile(image: $0, bidID: bid.id)
                .catchErrorJustReturn(false)
        }

        return Observable.zip([dataSaved] + photosSaved)
            .trackActivity(activityIndicator)
    }
    .asDriver(onErrorJustReturn: []) // remove this line if you want an Observable<[Bool]>.
person Daniel T.    schedule 16.08.2018
comment
Спасибо, я постараюсь. - person Denis Kutlubaev; 16.08.2018
comment
В качестве информации. Оператор zip не загружает изображения по одному. Он начнет все загрузки одновременно и сообщит, когда они все будут завершены. - person Daniel T.; 16.08.2018
comment
У меня возникает ошибка: Невозможно преобразовать значение типа '(Bid) -> Observable‹[Bool]›' в ожидаемый тип аргумента '() -> SharedSequence‹, _›' - person Denis Kutlubaev; 19.08.2018
comment
Что возвращают ваши функции CustomerManager? Я предполагал, что они вернули Observable‹Bool›. - person Daniel T.; 19.08.2018
comment
Да. Он возвращает Observable‹Bool› - person Denis Kutlubaev; 19.08.2018
comment
Посмотрите на мое окончательное решение ниже. Сделал по вашим идеям. Но я немного изменил свой первоначальный код, сначала добавив объект заявки на сервер и получив его идентификатор, а затем загрузив для него изображения. - person Denis Kutlubaev; 19.08.2018
comment
SharedSequence является водителем. Если вы хотите Observable<[Bool]>, просто удалите строку .asDriver.... - person Daniel T.; 19.08.2018

Окончательное решение

let bidID: Driver<Int> = saveTaps.withLatestFrom(newBid)
    .flatMapLatest { bid in
        return CustomerManager.shared.bidCreate(bid: bid)
            .trackActivity(activityIndicator)
            .asDriver(onErrorJustReturn: 0)
}

saveCompleted = Driver.combineLatest(bidID, newBid) { bidID, newBid in
    newBid.uploadedImages.map {
        CustomerManager.shared.bidUploadFile(image: $0, bidID: bidID).asDriver(onErrorJustReturn: false)
    }
    }.flatMap { imageUploads in
        return Driver.zip(imageUploads).trackActivity(activityIndicator).asDriver(onErrorJustReturn: [])
    }.map{ (results:[Bool]) -> Bool in
        return !results.contains(false)
}

Это комбинированная версия этого, которая эквивалентна:

let imageUploads: Driver<[Driver<Bool>]> = Driver.combineLatest(bidID, newBid) { bidID, newBid in
    newBid.uploadedImages.map {
        CustomerManager.shared.bidUploadFile(image: $0, bidID: bidID).asDriver(onErrorJustReturn: false)
    }
}

let photosSaved: Driver<[Bool]> = imageUploads.flatMap { imageUploads in
    return Driver.zip(imageUploads).trackActivity(activityIndicator).asDriver(onErrorJustReturn: [])
}

saveCompleted = photosSaved.map{ (results:[Bool]) -> Bool in
    return !results.contains(false)
}
person Denis Kutlubaev    schedule 16.08.2018