디폴트 매개변수
Compile 타임에 각 Composable 함수에 $default라는 메타데이터가 매개변수로 추가된다.
Composes는 Composable 함수에서 각 매개변수의 인덱스를 비트마스킹 기법으로 매핑하는 $default 매개변수를 통하여 디폴트 값을 가진 매개변수를 나타낸다.
이는 위에서 살펴본 $changed 매개변수와 동일한 방식으로 수행된다.
디폴트 값을 가지는 n개의 매개변수당 $default 매개변수를 하나씩 가지는데, $default 매개변수는 Composable 함수의 각 입력 매개변수에 대해 호출자 쪽에서 값을 제공하는지의 여부를 제공하고, 최종적으로 디폴트 값을 사용해야 할지, 호출자 쪽에서 넘겨주는 값을 사용해야 할지 결정한다.
아래의 코드에서는 $default 비트마스크 매개변수가 주입되기 전과 후의 Composable 함수의 형태와 디폴트 매개변수 값을 읽고 사용하는 사례를 명확하게 보여준다.
//Before compiler
@Composable
fun A(x: Int = 0) {
f(x)
}
//After compiler
@Composable
fun A(x: Int, $changed: Int, $default: Int) {
val x = if ($default and 0b1 != 0) 0 else x
f(x)
}
$changed 매개변수의 사례와 마찬가지로 비트의 조작이 수행되며, 디폴트 값에 대한 비교는 단순히 $default 매개변수를 사용한 비트마스킹을 통해 확인하고, x에 대해 전달된 값을 디폴트 값(0)으로 설정하거나 원본 값을 유지한다.
컨트롤 플로우 그룹 생성
Compose Compiler는 각 Composable 함수의 본문에 그룹을 삽입하며, 그 그룹의 유형은 아래와 같다.
- 교체 가능한 그룹
- 이동 가능한 그룹
- 재시작 가능한 그룹
Composable 함수는 Runtime시에 그룹을 생성하며, 생성된 그룹은 현 상태에 대한 정보를 보존한다.
이를 통해 composition은 그룹에 교체가 필요할 때 Composable의 정체성을 유지하고 데이터를 이동시킬 때, 또는 recomposition 중에 함수를 재시작할 때 쓰여진 데이터를 어떻게 처리해야 할지 알 수 있다.
또한 그룹은 Composable 함수의 호출 위치에 대한 정보를 가지고 있으므로 이를 통해 앞서 살펴봤던 위치 기억법을 가능하게 한다.
교체 가능한 그룹
Composable 람다식의 본문에 $composer, $key, Composable 람다식의 실체와 같은 값을 매개변수로 받는 Composable 팩토리 함수 호출을 삽입함으로써 Composable 람다식이 자동으로 감싸진다는 걸 배웠었다.
아래의 코드는 방금 언급한 팩토리 함수가 어떻게 생겼는지 보여준다.
fun composableLamda(
composer: Composer,
key: Int,
tracked: Boolean,
block: Any
) : ComposableLamda {
composer.startReplaceableGroup(key)
val slot = composer.rememberedValue()
val result = if (slot === Composer.Empty) {
val value = ComposableLamdaImpl(key, tracked)
composer.updateRememberedValue(value)
value
} else {
slot as ComposableLamdaImpl
}
result.update(block)
composable.endReplceableGroup()
return result
}
위 팩토리 함수는 Composable 람다식을 위해 호출되며 동작 방식은 먼저 key로 교체 가능한 그룹을 시작하고, 중간에 모든 텍스트 범위를 감싸고, 마지막으로 그룹을 닫는다.
이는 시작과 끝 호출 사이에서 composition을 관련성 있는 정보로 업데이트하는 것으로 우리가 래핑하는 람다식이다.
지금까지는 Composable 람다식이지만, 다른 Composable 함수의 호출 또한 동일하게 처리된다. 이어지는 아래의 코드는 @NonRestartableComposable 어노테이션으로 재시작이 불가능하다고 마킹된 Composable 함수의 코드가 어떻게 변화되는지 보여준다.
// Before Compiler
@NonRestartableComposable
@Composable
fun Foo(x: Int) {
Wat()
}
//After Compiler
@NonRestartableComposable
@Composable
fun Foo(x: Int, %composer: Composer?, %changed: Int) {
%composer.startReplaceableGroup(<>)
Wat(%composer, 0)
%composer.endReplaceableGroup()
}
위 Composable 함수 또한 composition에 저장하기 위한 교체 가능한 그룹을 생성한다.
그룹은 일종의 트리와 같으며 각 그룹은 원하는만큼의 그룹을 자식으로 가질 수 있다. 위의 예시에서 Wat() 함수 또한 Composable 함수라면, Compiler는 해당 함수에 대해서도 그룹을 삽입한다.
'Android' 카테고리의 다른 글
[Android] Compose 런타임 - (1) (0) | 2024.11.25 |
---|---|
[Android] Compose 컴파일러 - (8) (0) | 2024.11.22 |
[Android] Compose 컴파일러 - (6) (0) | 2024.11.20 |
[Android] Compose 컴파일러 - (5) (0) | 2024.11.19 |
[Android] Compose 컴파일러 - (4) (0) | 2024.11.18 |