0. 오늘은 무엇을 했는가
오늘은 늦게 일어났습니다.
저번에도 월요일이던데, 알람이 월요일에 안 울리는 오류가 있는 것 같습니다.
어쨌든, 일어나서 코드 카타를 빠르게 풀고
일일 스크럼을 진행한 후, 코틀린과 안드로이드 공부를 했습니다.
그리고 간단한 미니 프로젝트를 젯팩 컴포즈로 시작했습니다.
1. 코드 카타
[ 09:00 ~ 10:00 ]
오늘의 코드 카타는 프로세스 였습니다. 문제 자체가 그렇게 어렵지는 않았지만, 문제 내용 중에 신경 쓸 부분이 있었습니다.
운영체제의 역할 중 하나는 컴퓨터 시스템의 자원을 효율적으로 관리하는 것입니다. 이 문제에서는 운영체제가 다음 규칙에 따라 프로세스를 관리할 경우 특정 프로세스가 몇 번째로 실행되는지 알아내면 됩니다.
1. 실행 대기 큐(Queue)에서 대기중인 프로세스 하나를 꺼냅니다.
2. 큐에 대기중인 프로세스 중 우선순위가 더 높은 프로세스가 있다면 방금 꺼낸 프로세스를 다시 큐에 넣습니다.
3. 만약 그런 프로세스가 없다면 방금 꺼낸 프로세스를 실행합니다.
3.1 한 번 실행한 프로세스는 다시 큐에 넣지 않고 그대로 종료됩니다.
예를 들어 프로세스 4개 [A, B, C, D]가 순서대로 실행 대기 큐에 들어있고, 우선순위가 [2, 1, 3, 2]라면 [C, D, A, B] 순으로 실행하게 됩니다.
현재 실행 대기 큐(Queue)에 있는 프로세스의 중요도가 순서대로 담긴 배열 priorities와, 몇 번째로 실행되는지 알고싶은 프로세스의 위치를 알려주는 location이 매개변수로 주어질 때, 해당 프로세스가 몇 번째로 실행되는지 return 하도록 solution 함수를 작성해주세요.
여기서 큐 라는 개념이 나옵니다. 이 개념을 알고 있고, 코틀린에서 이에 해당하는 컬렉션도 제공하는 걸 알고 있지만,
그 문법을 어떻게 쓰는지까지는 몰랐기에, 저는 제 식대로 풀어봤습니다.
우선, 내림차순으로 나열시킨 배열 하나를 만들어줬습니다. 그리고, 받은 배열과 내림차순 배열을 비교해서,
순서를 체크해줬습니다. 그리고, 이렇게 내려가는 도중에 index가 만약 location과 같다면, 값을 return 해줬습니다.
아무래도 반복문을 사용한 만큼 시간복잡도는 별로 좋지 못했습니다.
class Solution {
fun solution(priorities: IntArray, location: Int): Int {
var answer = 0
val sequence = priorities.filter { it >= priorities[location] }.sortedDescending().toIntArray()
var now = 0
var index = 0
while(true) {
if(priorities[index] == sequence[now]) {
now++
if(index == location) {
return now
}
}
if(index == priorities.size - 1) index = -1
index++
}
}
}
그리고나서 다른 분의 풀이를 보니, ArrayDeque라는 컬렉션을 사용하는 걸 봤습니다.
아직 남은 컬렉션이 많으니, 천천히 이쪽도 공부해보면서, 알고리즘이나 자료구조도 공부해야 할 것 같습니다.
2. 코틀린 공부 - 내부 클래스, 동반 객체
[ 11:00 ~ 13:00 ]
내부 클래스는 지난주 공부했던 내포 클래스와 비슷하게 생겼습니다. 하지만 확실히 다릅니다.
내부 클래스는 inner 키워드를 앞에 붙여줘야 하고, 자신을 포함하는 클래스의 인스턴스에 대해 참조합니다.
그러므로, 클래스의 멤버들을 private이어도 사용할 수 있습니다.
내부 클래스는 상속도 할 수 있지만, 내포 클래스가 내부 클래스를 상속할 수는 없으며, 자식도 내부 클래스여야 합니다.
동반 객체는 지난주 공부했던 Object의 또다른 형태라고 보시면 될 것 같습니다.
companion object는 클래스 안에 들어갈 수 있습니다. companion object의 멤버들은 사실 그 클래스의 멤버들이나 다름없습니다.
companion object를 이름을 붙여줄 수 있으며, 이름을 붙이지 않으면, Companion()이라는 기본값을 갖게 됩니다.
companion object가 멤버와 다른 점은 companion object는 해당 클래스의 모든 인스턴스에 적용됩니다.
예를 들어,
class A {
companion object {
var a: Int = 0
fun increase() = a++
}
}
fun main() {
val a1 = A()
val a2 = A()
a1.increase()
a2.increase()
}
위에서 a는 1이 아닌 2가 됩니다. 즉, 모든 인스턴스에서 공유하는 객체입니다.
다음은 제네릭스를 공부할지, 확장 함수 쪽을 공부할지 고민 중입니다...
3. 안드로이드 공부
[ 14:00 ~ 17:00 ]
오늘 안드로이드 공부는 Composition Local, Slot API, Modifier에 대해 공부했습니다.
먼저 Composition Local은 특정 범위의 지역에 적용할 수 있는 값이라고 보면 될 것 같습니다.
기본적으로 갖고 있는 LocalContext 같은 것도 있고, 직접 생성할 수도 있습니다.
val com1 = compositionLocalOf { 초기값 }
val com2 = staticCompositionLocalOf { 초기값 }
static이 들어간 경우는 정적이라는 의미로, 값이 자주 안 바뀔 때 씁니다.
위처럼 만들어두고, 다음과 같이 쓸 수 있습니다.
CompositionLocalProvider (com1 provides 값) {
//적용할 컴포저블
}
이렇게 하면, 해당 컴포저블과 그 아래에 있는 컴포저블에 위 사항이 전달됩니다. 그리고, 해당하는 컴포저블들에서는
com1.current
를 사용해서 위 값을 적용시킬 수 있습니다.
한 번에 여러 범위를 적용시킬 수 있기에 유용하지만, 너무 많이 사용하면 코드가 복잡해질 수 있다는 걸 알아야 합니다.
3-1. Slot API
슬롯 API는 우리가 아는 슬롯처럼 컴포저블을 다룬다는 뜻입니다.
매개변수에다가 @Composable -> Unit. 즉, 컴포저블을 받을 수 있게끔 만들어두고, 해당 변수를 특정 위치에다가
설정만 해두면, 동적으로 컴포저블을 다룰 수 있게 됩니다.
@Composable
fun TestScreen(middleContent: @Composable -> Unit) {
Column {
Text()
middleContent()
Button()
}
}
위처럼 TextScreen에 어떤 인자가 들어가냐에 따라 가운데 화면이 바뀌게 됩니다.
3-2. Modifier
모디파이어는 간단하게 말해서, 설정입니다.
padding이나, size를 바꿀 수도 있고, clickable로 만들 수도 있습니다.
기본적으로 왠만한 Composable 함수들의 첫 선택 매개변수로 지정돼 있습니다.
Modifier는 다양한 확장함수를 갖고 있기에, 이는 내일 더 다뤄보도록 하겠습니다.
4. 안드로이드 미니 프로젝트 - 오목조목
[ 17:00 ~ 18:00 ]
이 앱같은 경우는 다양한 미니게임들을 추가해, 젯팩 컴포즈에 익숙해지고,
알고리즘을 짜보면서, 알고리즘에 더 익숙해지기 위해 시작했습니다.
이름이 오목조목인 이유는 오목이 일단 최종 목표이기 때문이기도 하고,
다양한 미니 게임들이 있다는 의미도 담고 있습니다.
아무래도, 2D, 3D 그래픽이 그렇게 많이 들어가는 앱으로 만들 생각은 없기 때문에,
안드로이드 스튜디오를 사용해서 충분히 만들 수 있다고 생각합니다.
일단은 가위바위보 입니다.
가위바위보 같은 경우엔 텍스트와 사진만 있으면 만들기가 가능하고,
알고리즘도 되게 쉽기 때문에, 먼저 젯팩 컴포즈에 익숙해지기 위해 선택했습니다.
물론, 이 프로젝트를 만들면서 MDC로 만드는 방식도 캠프를 통해 계속 공부하고,
과제와 프로젝트도 진행될 것이기 때문에 양쪽을 다 잡기 위해 노력해야 할 것 같습니다.
5. 끝
오늘은 이렇게 끝이 났습니다.
근데요. 제가 지각한 건 너무 억울한데요...
내일은 수준별 학습반이 있습니다.
엄청 어려운 수업을 아닐 것 같습니다.
열심히 배우고, 잘 써볼 생각입니다.
끝.