Has anyone else encountered iOS compiling issues r...
# touchlab-tools
m
Has anyone else encountered iOS compiling issues related to Semaphore when using SKIE content? Wrote up an issue with more details here . There seems to be a collision with the Darwin.Semaphore and the generated KMM.Semaphore. We do not get this issue when creating the framework without SKIE
t
Thanks Mike for reporting this. We'll definitely look into it! It's weird that our test suite didn't catch it as we're testing against over a thousand of libraries in Maven Central.
All of us working on SKIE are on Droidcon NYC this week, so we'll hopefully get to it next week 🙂
m
Enjoy Droidcon! If there’s any more information I can provide (now or next week) please let me know
t
Actually, could you share the code where you expose Semaphore from your Kotlin? That'll probably make it easier for me to repro it
m
We didn’t intentionally expose Semaphore anywhere, but I can share more of the gradle file we use to build the XCFramework. Better to send here in slack or add to the GitHub issue?
t
The github issue is probably a better place for that, thanks!
m
Updated the issue with our Gradle file. None of the projects there use Semaphore directly but they do use coroutines which is the only part I could think of that would be related.
t
I think it's gonna be this export.
That should be easy to reproduce
👍 1
Aside from that, I definitely recommend not exporting coroutines, it's a ton of code that will blow up your binary size and compilation time
m
And instead internalize any reference and usage of coroutine scopes inside of KMM, and have all publicly exposed methods not requires scopes to be provided?
t
Definitely. I wonder, how do you use the scopes?
m
In KMM, we have the following:
Copy code
/// Convenience object for accessing common coroutine scopes from iOS.
class CoroutineScopes {
  companion object {
    val MainScope = kotlinx.coroutines.MainScope()
    val DefaultScope = kotlinx.coroutines.CoroutineScope(kotlinx.coroutines.Dispatchers.Default)
  }
}
Then we created a test class, specifically because on the Android side we wanted to expose coroutine scopes:
Copy code
/**
 * This class exists for the purpose of testing functionality from KMP in the target platforms
 * (such as iOS and Android).
 *
 * This is intended to be public and published with each release of the library to allow downstream
 * clients to test out new functionality and behaviours.
 *
 * If this gets sufficiently large, move it to it's own module so that it may include content from
 * any module.
 */
class TestClass {
  companion object {
    /**
     * Static getter to test static functionality.
     */
    fun getInstance(): TestClass {
      return TestClass()
    }

    private val staticMutatingString = "Something to mutate"
    private val staticString = "Static String"
  }

  // Some code removed for readability

  /// Function which allows defining the scope to launch the work in.
  fun doWorkWithScope(scope: CoroutineScope) {
    scope.launch {
      printTest("Background!")
    }
  }

  suspend fun printTest(input: String): String {
    /// Use a Coroutine to make the input capitalized on a non-main thread.
    return withContext(Dispatchers.Default) {
      println(input)
      input.replaceFirstChar { if (it.isLowerCase()) it.titlecase() else it.toString() }
    }
  }
}
Which we then tested on the iOS side:
Copy code
func test_doWorkWithScope() {
    sut = TestClass.Companion.getInstance(TestClass.Companion.shared)()
    sut.doWorkWithScope(scope: CoroutineScopeKt.MainScope())
  }
They are not used yet, but the plan is to use them as they would be in Android app development I believe (I come from an iOS development background, so my knowledge there is not as strong)
t
That's really interesting. It's a little weird to do it this way.
m
When my Android colleague is available, they might be able to provide more context on why we want to expose the scopes. But this is sounding like we should look at internalizing them.