I'm working in a fresh Kotlin Multiplatform mobile project, and I am having trouble implementing a Kotlin interface into a Swift class.
Here is my setup:
From kotlin common (shared) module:
interface LocalUserSource {
suspend fun saveUser(user: User): Boolean
suspend fun readUser(): User?
}
Implementing the protocol in Swift (I believe the protocol is generated by Kotlin/Native):
class DBUserSource : LocalUserSource {
func readUser(completionHandler: @escaping (common.User?, Error?) -> Void) {
// read user from core data
}
func saveUser(user: common.User, completionHandler: @escaping (KotlinBoolean?, Error?) -> Void) {
// save user with core data
}
}
The Xcode project is able to see the generated common framework, and I am able to jump to class / protocol definitions within the framework
But building the Xcode project continually results in this error:
Type 'DBUserSource' does not conform to protocol 'LocalUserSource'
When I use the "Fix" option in Xcode, it continually duplicates the method over and over and shows the same error. I've tried everything to clean both android studio (where I'm running the gradle build) and Xcode.
What's odd is, I've seen this work. I've saved and read users to core data, but today I cannot get the iOS side of things to work. Just wondering if anyone has experienced anything similar, and has any pointers.
Also here is the objective-c definition from the common framework:
__attribute__((swift_name("LocalUserSource")))
@protocol CommonLocalUserSource
@required
- (void)readUserWithCompletionHandler:(void (^)(CommonUser * _Nullable_result, NSError * _Nullable))completionHandler __attribute__((swift_name("readUser(completionHandler:)")));
- (void)saveUserUser:(CommonUser *)user completionHandler:(void (^)(CommonBoolean * _Nullable, NSError * _Nullable))completionHandler __attribute__((swift_name("saveUser(user:completionHandler:)")));
@end;
CodePudding user response:
suspend fun readUser(): User?
is a nullable in your Kotlin code, whereas you're using a non-nullable/non-optional type in the Swift equivalent function signature:
func readUser(completionHandler: @escaping (common.User, Error?) -> Void) {
// read user from core data
}
// The above should be
func readUser(completionHandler: @escaping (common.User?, Error?) -> Void) {
// read user from core data
}
CodePudding user response:
So I finally figured it out. I had a generic Result class in my common module that looked like this:
sealed class Result<out T : Any>
class Success<out T : Any>(val data: T) : Result<T>()
class Error(private val exception: Throwable, val message: String? = exception.message) : Result<Nothing>()
inline fun <T : Any> Result<T>.onSuccess(action: (T) -> Unit): Result<T> {
if (this is Success) action(data)
return this
}
inline fun <T : Any> Result<T>.onError(action: (Error) -> Unit): Result<T> {
if (this is Error) action(this)
return this
}
Once I removed this, I no longer saw the implementation error in the Swift code and the project ran. Honestly, no idea why. I assume something with generics and Kotlin/Native. But, if anyone has any idea, I'd love to know!