Метод экземпляра 'drive' требует, чтобы типы 'NotificationItem' и '[NotificationItem]' были эквивалентными - PullRequest
3 голосов
/ 01 ноября 2019

Я создал класс под названием элемент уведомления и анализ данных из класса модели RTVNotification

import Foundation import RTVModel

открытый класс NotificationItem: NSObject {

public var id: String
public var title: String
public var comment: String
public var publishStartDateString: String

init(id: String,
     title: String,
     comment: String,
     publishStartDateString: String) {
    self.id = id
    self.title = title
    self.comment = comment
    self.publishStartDateString = publishStartDateString

    super.init()
}

}

расширение NotificationItem {экземпляр статической функции (с уведомлением: RTVNotification) -> NotificationItem? {

    return NotificationItem(
        id: notification.id,
        title: notification.title,
        comment: notification.comment,
        publishStartDateString: notification.publishStartDateString)

}

}

ViewModel

открытый класс SettingsViewModel: ViewModel {

var item = [NotificationItem]()

public var fetchedNotifications: Driver<NotificationItem> = .empty()

public var apiErrorEvents: Driver<RTVAPIError> = .empty()

public var notificationCount: Driver<Int> = .empty()

public func bindNotificationEvents(with trigger: Driver<Void>) {

    let webService: Driver<RTVInformationListWebService> = trigger
        .map { RTVInformationListParameters() }
        .webService()

    let result = webService.request()
    apiErrorEvents = Driver.merge(apiErrorEvents, result.error())
    notificationCount = result.success().map {$0.informationList.maxCount }
    fetchedNotifications =
         result.success()
        .map {$0.informationList.notifications}

-----> .map {NotificationItem. instantiate (with: $ 0)}

}

}

Получение сообщения о том, что невозможно преобразовать значение типа '[RTVNotification]' в ожидаемый тип аргумента 'RTVNotification' Что я могу сделать длярешить это.

Ответы [ 2 ]

2 голосов
/ 02 ноября 2019

Ваша проблема здесь: fetchedNotifications: Driver<NotificationItem> должно быть fetchedNotifications: Driver<[NotificationItem]>, а для строки .map {NotificationItem.instantiate(with: $0)} нужна другая карта. Вы имеете дело с Observable<Array<RTVNotification>>. У вас есть тип контейнера внутри типа контейнера, поэтому вам нужна карта внутри карты:

.map { $0.map { NotificationItem.instantiate(with: $0) } }

Когда ваши типы не совпадают, вам нужно изменить типы.

Другоепроблемы с вашим кодом ...

  • Драйверы, наблюдаемые, предметы и реле никогда не должны быть определены с var, они всегда должны быть let с. Объекты, которые подписываются на ваши свойства до вызова привязки, будут подключаться к наблюдаемым .empty() и никогда не получат никаких значений. В конце концов, это функциональное реактивное программирование.

  • Ваш тип NotificationItem должен быть либо struct, либо все его свойства должны быть `Let's.

Обязательно прочитайте и поймите ответ @ par на этот вопрос. Он написал действительно хорошее объяснение, и было бы стыдно тратить эту передачу знаний.

2 голосов
/ 01 ноября 2019

Цель функции map() состоит в том, чтобы перебрать элементы входного массива и применить функцию преобразования к каждому из этих элементов. Преобразованные элементы добавляются в новый выходной массив, который возвращается map(). Важно понимать, что длина выходного массива равна длине входного массива.

Например:

let inputArray = ["red", "white", "blue"]
let outputArray = inputArray.map { $0.count } // outputArray is [3, 5, 4]

В вашем коде вы вызываете:

result.success().map { $0.informationList.notifications }

Я вообще не знаю RxSwift, поэтому я собираюсь вдаваться в дикие спекуляции.

Во-первых, я не знаю точно, что возвращает result.success(), но тот факт, что выМожно вызвать map(), это означает, что result.success() возвращает массив (что странно, но хорошо, мы пойдем с ним).

Во-вторых, мы знаем, что массив, возвращаемый result.success(), содержит элементы, которые имеютсвойство informationList, а свойство informationList имеет свойство с именем notifications. Я предполагаю, что notifications во множественном числе означает, что тип свойства notifications является массивом, вероятно, [RTVNotification].

Итак, этот код:

result.success().map { $0.informationList.notifications }

Преобразует массив success() в новый массив. Исходя из моего предположения, что notifications относится к типу [RTVNotification], и, если предположить, что массив success() содержит только один элемент, я ожидаю, что результат

result.success().map { $0.informationList.notifications }

Toбыть массивом типа [[RTVNotification]], то есть массивом с одним элементом, где этот элемент является массивом RTVNotification s.

Затем вы передаете этот массив [[RTVNotification]] в другую функцию map():

.map { NotificationItem.instantiate(with: $0) }

Напомним с самого начала этого ответа, что map() перебирает элементы массивов. Поскольку входной массив для этой карты [[RTVNotification]], его элементы будут иметь тип [RTVNotification]. Вот что означает $0 в вашем вызове - [RTVNotification]. Но функция instantiate(with:) принимает RTVNotification, , а не массив RTVNotification, поэтому вы получаете ошибку:

Невозможно преобразовать значение типа '[RTVNotification]'к ожидаемому типу аргумента' RTVNotification '

Так что вы можете сделать, чтобы это исправить?

Я бы, вероятно, сделал что-то подобное (вам придется адаптировать его для вашего использованияcase):

guard let successResponse = webService.request().success().first else {
    print("no success response received")
    return nil // basically report up an error here if not successful
}

// get the list of notifications, this will be type [RTVNotification]
let notifications = successResponse.informationList.notifications

// Now you can create an array of `[NotificationItem]` like you want:
let notificationItems = notifications.map { NotificationItem.instantiate(with: $0) }

// do something with notificationItems...

Предостережение к вышесказанному: если вам нужно перебирать каждый элемент массива success(), то вы можете сделать это следующим образом:

let successResponses = webService.result().success()

// successNotifications is of type [[RTVNotification]]
let successNotifications = successResponses.map { $0.informationList.notifications }

// successItems will be of type [[NotificationItem]]
let successItems = successNotifications.map { notifications in
    notifications.map { NotificationItem.instantiate(with: $0) }
}

Другими словами, в этом последнем случае вы получите массив, содержащий массивы NotificationItem.

...