Compose Multiplatform runtime library for iOS UIKit x64 target providing core runtime functionality for declarative UI framework integration.
—
Side effect management with lifecycle-aware execution and automatic cleanup. Effects provide safe ways to perform operations outside the composition scope while integrating properly with the Compose lifecycle.
Effect that requires cleanup when the effect leaves the composition or its keys change.
/**
* Effect that runs when keys change and provides cleanup via DisposableEffectResult
* @param key1 Key that determines when effect should restart
* @param effect Lambda that runs the effect and returns cleanup
*/
@Composable
fun DisposableEffect(
key1: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
): Unit
/**
* DisposableEffect with two key dependencies
* @param key1 First key dependency
* @param key2 Second key dependency
* @param effect Lambda that runs the effect and returns cleanup
*/
@Composable
fun DisposableEffect(
key1: Any?,
key2: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
): Unit
/**
* DisposableEffect with three key dependencies
* @param key1 First key dependency
* @param key2 Second key dependency
* @param key3 Third key dependency
* @param effect Lambda that runs the effect and returns cleanup
*/
@Composable
fun DisposableEffect(
key1: Any?,
key2: Any?,
key3: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
): Unit
/**
* DisposableEffect with multiple key dependencies
* @param keys Variable number of key dependencies
* @param effect Lambda that runs the effect and returns cleanup
*/
@Composable
fun DisposableEffect(
vararg keys: Any?,
effect: DisposableEffectScope.() -> DisposableEffectResult
): Unit
/**
* Scope for DisposableEffect providing cleanup mechanism
*/
interface DisposableEffectScope {
/**
* Creates a cleanup handler
* @param onDispose Function called when effect is disposed
* @return DisposableEffectResult for the effect
*/
fun onDispose(onDispose: () -> Unit): DisposableEffectResult
}
/**
* Result of a DisposableEffect containing cleanup logic
*/
interface DisposableEffectResultUsage Examples:
@Composable
fun DisposableEffectExample(userId: String) {
// Effect that depends on userId
DisposableEffect(userId) {
val subscription = userService.subscribeToUser(userId) { user ->
// Handle user updates
}
// Cleanup when userId changes or composable leaves composition
onDispose {
subscription.cancel()
}
}
// iOS-specific example: Observer pattern
DisposableEffect(Unit) {
val observer = NotificationCenter.default.addObserver(
forName: UIApplication.didBecomeActiveNotification,
object: null,
queue: OperationQueue.main
) { _ ->
// Handle app becoming active
}
onDispose {
NotificationCenter.default.removeObserver(observer)
}
}
}Effect that launches a coroutine and automatically cancels it when the effect leaves the composition.
/**
* Launches a coroutine in the composition scope
* @param key1 Key that determines when to restart the coroutine
* @param block Suspending function to execute in the coroutine
*/
@Composable
fun LaunchedEffect(
key1: Any?,
block: suspend CoroutineScope.() -> Unit
): Unit
/**
* LaunchedEffect with two key dependencies
* @param key1 First key dependency
* @param key2 Second key dependency
* @param block Suspending function to execute in the coroutine
*/
@Composable
fun LaunchedEffect(
key1: Any?,
key2: Any?,
block: suspend CoroutineScope.() -> Unit
): Unit
/**
* LaunchedEffect with three key dependencies
* @param key1 First key dependency
* @param key2 Second key dependency
* @param key3 Third key dependency
* @param block Suspending function to execute in the coroutine
*/
@Composable
fun LaunchedEffect(
key1: Any?,
key2: Any?,
key3: Any?,
block: suspend CoroutineScope.() -> Unit
): Unit
/**
* LaunchedEffect with multiple key dependencies
* @param keys Variable number of key dependencies
* @param block Suspending function to execute in the coroutine
*/
@Composable
fun LaunchedEffect(
vararg keys: Any?,
block: suspend CoroutineScope.() -> Unit
): UnitUsage Examples:
@Composable
fun LaunchedEffectExample(searchQuery: String) {
var searchResults by remember { mutableStateOf<List<SearchResult>>(emptyList()) }
// Launch search when query changes
LaunchedEffect(searchQuery) {
if (searchQuery.isNotEmpty()) {
delay(300) // Debounce
try {
searchResults = searchService.search(searchQuery)
} catch (e: Exception) {
// Handle error
}
}
}
// Launch periodic update
LaunchedEffect(Unit) {
while (true) {
delay(30_000) // 30 seconds
refreshData()
}
}
}
@Composable
fun NetworkStatusExample() {
var isOnline by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
networkMonitor.status.collect { status ->
isOnline = status == NetworkStatus.Connected
}
}
}Effect that executes after every successful recomposition.
/**
* Executes a side effect after every recomposition
* @param effect Function to execute after recomposition
*/
@Composable
fun SideEffect(effect: () -> Unit): UnitUsage Examples:
@Composable
fun SideEffectExample(user: User) {
// Log every time this composable recomposes
SideEffect {
logger.log("UserProfile recomposed for user: ${user.id}")
}
// Update analytics after recomposition
SideEffect {
analytics.track("profile_viewed", mapOf("user_id" to user.id))
}
}
@Composable
fun UIKitIntegrationExample() {
val currentUser by viewModel.currentUser.collectAsState()
// Update UIKit view after recomposition
SideEffect {
navigationController.title = currentUser?.name ?: "Profile"
}
}Returns a CoroutineScope that's automatically cancelled when the composition leaves.
/**
* Returns a CoroutineScope bound to the composition lifecycle
* @return CoroutineScope that's cancelled when composition is disposed
*/
@Composable
fun rememberCoroutineScope(): CoroutineScope
/**
* Returns a CoroutineScope bound to the composition lifecycle with custom context
* @param getContext Function to provide custom coroutine context
* @return CoroutineScope with custom context that's cancelled when composition is disposed
*/
@Composable
fun rememberCoroutineScope(getContext: () -> CoroutineContext): CoroutineScopeUsage Examples:
@Composable
fun CoroutineScopeExample() {
val scope = rememberCoroutineScope()
val snackbarHostState = remember { SnackbarHostState() }
Column {
Button(onClick = {
// Launch coroutine in response to user action
scope.launch {
try {
val result = performNetworkCall()
snackbarHostState.showSnackbar("Success: $result")
} catch (e: Exception) {
snackbarHostState.showSnackbar("Error: ${e.message}")
}
}
}) {
Text("Perform Action")
}
SnackbarHost(hostState = snackbarHostState)
}
}
@Composable
fun CustomCoroutineScopeExample() {
// Custom scope with IO dispatcher for background work
val ioScope = rememberCoroutineScope { Dispatchers.IO }
// Custom scope for iOS main thread operations
val mainScope = rememberCoroutineScope { IOSMainDispatcher }
Button(onClick = {
// Heavy computation on IO dispatcher
ioScope.launch {
val data = performHeavyComputation()
// Switch to main thread for UI updates
mainScope.launch {
updateUI(data)
}
}
}) {
Text("Process Data")
}
}Remembers a value that's always up-to-date in long-running effects.
/**
* Remembers a value that's always current in long-running operations
* @param newValue The current value to remember
* @return State containing the most recent value
*/
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T>Usage Examples:
@Composable
fun TimerExample(onTimeout: () -> Unit) {
// Remember the latest callback to avoid stale captures
val currentOnTimeout by rememberUpdatedState(onTimeout)
LaunchedEffect(Unit) {
delay(5000) // 5 second timer
currentOnTimeout() // This will call the latest onTimeout
}
}
@Composable
fun IntervalExample(interval: Long, action: () -> Unit) {
val currentAction by rememberUpdatedState(action)
LaunchedEffect(interval) {
while (true) {
delay(interval)
currentAction() // Always uses the latest action
}
}
}@Composable
fun ErrorHandlingExample() {
var error by remember { mutableStateOf<String?>(null) }
LaunchedEffect(Unit) {
try {
performRiskyOperation()
} catch (e: Exception) {
error = e.message
}
}
error?.let { errorMessage ->
Text("Error: $errorMessage", color = Color.Red)
}
}@Composable
fun CancellationExample(shouldRun: Boolean) {
LaunchedEffect(shouldRun) {
if (shouldRun) {
try {
while (true) {
performPeriodicTask()
delay(1000)
}
} catch (e: CancellationException) {
// Cleanup on cancellation
cleanup()
throw e // Re-throw to properly handle cancellation
}
}
}
}@Composable
fun ComplexDependenciesExample(
userId: String,
refreshTrigger: Int,
settings: UserSettings
) {
// Effect runs when any dependency changes
LaunchedEffect(userId, refreshTrigger, settings.theme) {
loadUserData(userId, settings)
}
}@Composable
fun IOSMainThreadExample() {
LaunchedEffect(Unit) {
// Switch to main dispatcher for UI updates
withContext(Dispatchers.Main.immediate) {
updateUIKitView()
}
}
}@Composable
fun BackgroundTaskExample() {
DisposableEffect(Unit) {
val taskId = UIApplication.shared.beginBackgroundTask {
// Background task expired
}
onDispose {
UIApplication.shared.endBackgroundTask(taskId)
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-compose-runtime--runtime-uikitx64