https://kotlinlang.org logo
#touchlab-tools
Title
# touchlab-tools
с

Стефан Јовановић

11/12/2023, 10:25 AM
This is my function that returns the RequestState wrapped in the flow:
Copy code
fun fetchProducts(limit: Int):  Flow<RequestState<List<Product>>> {
    return flow {
        emit(RequestState.Loading)
        // Delay to show a loading state.
        delay(2000)
        try {
            emit(
                RequestState.Success(
                    data = httpClient.get(urlString = "${baseUrl}products?limit=$limit").body()
                )
            )
        } catch (e: Exception) {
            emit(RequestState.Error(e.message.toString()))
        }
    }
}
f

Filip Dolník

11/12/2023, 11:33 AM
Unfortunately this is not possible in this specific case due to a limitation of Obj-C. The problem is that the
List<Product>
type is usually converted to
[Product]
- which would retain the type. However, here the type is used as a type argument (in generics) which cannot be converted to
[Product]
( Swift Array) because it’s not a reference type which is required for Obj-C type arguments. Therefore it’s automatically converted by the Swift compiler to
NSArray
instead - which does not have generics in Swift and therefore the
Product
type is lost. (but if you had just
RequestState<Product>
then it would work)
с

Стефан Јовановић

11/12/2023, 11:58 AM
@Filip Dolník I thought of that, I've made another data class Products, that has only one property:
val items: List<Product>
If I understand correctly, the subclasses of a sealed class will be converted as regular classes in Swift. As a someone who's coming from Android world, I would want to declare a variable something like:
Copy code
val fetchedProducts: MutableState<RequestState<Products>> = remember {
    mutableStateOf(RequestState.Idle)
}
LaunchedEffect(key1 = Unit) {
    ProductApi().fetchProducts(limit = 10).collectLatest {
        fetchedProducts.value = it
    }
}
But in swift a RequestStateIdle class is not recognized as a subclass of RequestState? 🤔
f

Filip Dolník

11/12/2023, 12:36 PM
Yeah, that’s because Swift generics do not support covariance. It would work if you defined the RequestState.Idle as
class Idle<T> : RequestState<T>
and then in Swift wrote
= RequestStateIdle<Products>()
actually, in this case you might get away with hard casting the object meaning:
Copy code
response: RequestState<Products> = RequestStateIdle() as!  RequestState<Products>
That wouldn’t work with Swift objects but with Obj-C objects it should.
с

Стефан Јовановић

11/12/2023, 12:52 PM
@Filip Dolník Thanks Filip, I'll continue exploring it furthermore, will try your suggestions. Good tips.
Or maybe even some functions inside the sealed class like: isError() = this is RequestState.Error, isLoading(), isSuccess()... 🤔
So we don't use switch expression, but those functions instead.
f

Filip Dolník

11/13/2023, 7:30 AM
as for the crash: hm, the problem in this case seems to be that Nothing does not behave the same way in Kotlin and Obj-C. In Kotlin it’s a subtype of all types, however, such concept doesn’t exist in Obj-C / Swift so it’s a regular class.
2 Views