Rxswift - Generic Parameter 'Self' Could Not Be Inferred

Generic parameter 'Result' could not be inferred with RxSwift

In order for type inference to work in closures, you generally need either the outer scope to know the type or the closure itself needs to be one line. This is a limitation in the Swift type system. So either:

htmlHelper.fetchHtmlObservable(url) // this one is an Observable<String> function
.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
.map {
ParsingTypeFactory.getParsingType(parsingType: self.parsingType).parseActionItems(document: $0)
}

or

let myItems: Observable<[MyItem]> = htmlHelper.fetchHtmlObservable(url) // this one is an Observable<String> function
.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
.map {
let parsingHelper = ParsingTypeFactory.getParsingType(parsingType: self.parsingType)
return parsingHelper.parseActionItems(document: $0)
}

Other options:

Note that in all of the cases discussed so far, you are holding a strong reference to self and likely causing a memory cycle/leak. You can avoid that by making a helper function that isn't part of the class:

// do NOT put this in the class, make it a free function (possibly private to avoid namespace pollution.)
func parser(for parsingType: ParsingType) -> (Document) -> [MyItem] {
return { document in
let parsingHelper = ParsingTypeFactory.getParsingType(parsingType: parsingType)
return parsingHelper.parseActionItems(document: document)
}
}

And now the code in question becomes:

let myItems = htmlHelper.fetchHtmlObservable(url) // this one is an Observable<String> function
.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
.map(parser(for: parsingType))

If you don't like the idea of a free function, or you don't like a function that returns a function, you can put the function in an extension on ParserType:

extension ParsingType {
func parser(document: Document) -> [MyItem] {
let parsingHelper = ParsingTypeFactory.getParsingType(parsingType: self)
return parsingHelper.parseActionItems(document: document)
}
}

and now the original code becomes:

let myItems = htmlHelper.fetchHtmlObservable(url) // this one is an Observable<String> function
.subscribeOn(ConcurrentDispatchQueueScheduler.init(qos: .background))
.map(parsingType.parser(document:))

This also avoids keeping a reference to self.

RxSwift - Generic parameter 'Self' could not be inferred

I would suggest you to use the latest version of RxSwift. What you're using right now is deprecated. Your error may be related to it.

There are two ways to do what you're doing:

let countryArray = ["Bangladesh", "India", "Pakistan", "Nepal", "Bhutan", "China", "Malaysia", "Myanmar", "Sri Lanka", "Saudi Arabia"]
let countries = Observable.of(countryArray)

// Be sure to register the cell
tableView.register(UINib(nibName: "MyCell", bundle: nil), forCellReuseIdentifier: "myCell")
  1. To provide the cell type in the items(cellIdentifier:cellType:), that's basically what you are doing:

    countries
    .bind(to: tableView.rx.items(cellIdentifier: "myCell", cellType: MyCell.self)) { (row, element, cell) in
    // configure cell
    }
    .disposed(by: disposeBag)
  2. To provide the cell factory closure, in other words dequeue the cell in the closure and return it:

    countries
    .bind(to: tableView.rx.items) { (tableView, row, element) in
    let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: IndexPath(row: row, section: 0)) as! MyCell
    // configure cell
    return cell
    }
    .disposed(by: disposeBag)

Both have pros and cons. The second one has a reference to the tableView which sometimes can be very handy.

RxDataSources `Generic parameter 'Self' could not be inferred`

The Rx stream you bind to your RxTableViewSectionedReloadDataSource has to be of type Observable<[ActiveOrdersSection]>. I don't know exactly what your types are in this example because the code you provided is not enough but
I think that by using .map { Observable.just($0.items) } the result stream will be of type Observable<Observable<[Order]>>.
Try to change it to:
.map { [ActiveOrdersSection(header: "Your Header", orders: 0.items)] }

error: generic parameter 'T' could not be inferred in swift

You have to tell the compiler the type of T.

func makeFlatArrayGeneric<T>(_ array: [Any]) -> [T] {
var flatArray = [T]()
for item in array {
if let item = item as? T {
flatArray.append(item)
} else if let item = item as? [Any] {
let result: [T] = makeFlatArrayGeneric(item)
flatArray += result
}
}
return flatArray
}

let array: [Any] = [1, 2, [3], [4, [5]]]
let items: [Int] = makeFlatArrayGeneric(array) //[1, 2, 3, 4, 5]

A more functional approach to solving your problem.

extension Array {
func flatten() -> Array<Element> {
return self.flatMap({ element -> [Element] in
if let array = element as? Array {
return array.flatten()
} else {
return [element]
}
})
}
}

let items: [Int] = array.flatten() //[1, 2, 3, 4, 5]

RxSwift - optional issue on binding to tableView

You see this error because the compiler cannot infer the type of the Optional variable users passed into the following functions which work on generics and need to be able to infer the type.

An Optional in Swift is actually implemented as shown below. I guess in case of an Optional being potentially nil aka .none the compiler cannot infer the type for methods like e.g. items and bind(to:) which work on generics.

public enum Optional<Wrapped> : ExpressibleByNilLiteral {

/// The absence of a value.
///
/// In code, the absence of a value is typically written using the `nil`
/// literal rather than the explicit `.none` enumeration case.
case none

/// The presence of a value, stored as `Wrapped`.
case some(Wrapped)

/// Creates an instance that stores the given value.
public init(_ some: Wrapped)
//...
}

Workaround 1.): You could just use filterNil() (RxOptionals lib) to avoid the problem.

private func bind() {
users.asObservable().filterNil().bind(to:
tableView.rx.items(cellIdentifier: "UserCell",
cellType: UITableViewCell.self)) { (index, user, cell) in
// Cell setup.
}.disposed(by: disposeBag)
}

Workaround 2.): Make users non-optional. If you have no users just set an empty array as value.

let users: Variable<[User]> = Variable<[User]>([])

Workaround 3.): Use Nil-Coalescing Operator ?? in map function like

private func bind() {
users.asObservable().map { optionalUsers -> [User] in
return optionalUsers ?? []
}
.bind(to:
tableView.rx.items(cellIdentifier: "UserCell",
cellType: UITableViewCell.self)) { (index, user, cell) in
// Cell setup.
}.disposed(by: disposeBag)
}

Sidenote: Variable is deprecated in the latest version of RxSwift

Just for reference:

Implementation of items

public func items<S: Sequence, Cell: UITableViewCell, O : ObservableType>
(cellIdentifier: String, cellType: Cell.Type = Cell.self)
-> (_ source: O)
-> (_ configureCell: @escaping (Int, S.Iterator.Element, Cell) -> Void)
-> Disposable
where O.E == S {
return { source in
return { configureCell in
let dataSource = RxTableViewReactiveArrayDataSourceSequenceWrapper<S> { (tv, i, item) in
let indexPath = IndexPath(item: i, section: 0)
let cell = tv.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as! Cell
configureCell(i, item, cell)
return cell
}
return self.items(dataSource: dataSource)(source)
}
}
}

Implementation of bind(to:)

public func bind<O: ObserverType>(to observer: O) -> Disposable where O.E == E {
return self.subscribe(observer)
}


Related Topics



Leave a reply



Submit