기하학이 한 방울 들어간 유니온 파인드 문제. 이전에 풀다가 포기했던 문제다. 거리 계산 부분에서 아무 생각 없이 2차원 배열로서의 거리로 접근했는데, 옳은 방법이 아니었다. 2차원 배열 없이 풀 수 있는 문제.
풀이
입력되는 좌표와 범위를 입력받을 때마다, 모아놓은 나머지 지점들과의 거리를 계산, 범위가 겹치는 경우 유니온을 수행하여 마지막에 그룹의 개수를 출력하면 된다. 이번에는 그룹의 노드 개수를 파악하는 문제는 아니므로, 합병 수행 시 루트의 값은 바꾸지 않고 자식으로 들어갈 노드의 번호만 루트의 번호로 바꾸어 주면 된다. 두 지점의 범위 판정은 간단하다. 두 원점 사이의 거리가 두 지점의 범위의 총합보다 같거나 짧은 경우, 범위가 겹치는 것으로 판단하면 된다.
iOS 개발자라면 가장 근본적으로 알아야 할 App life Cycle에 관련된 질문이다. 질문에 대해 단답식으로 대답하자면 아래와 같이 대답할 수 있다.
"UIApplication 객체가 생성됩니다."
사용자가 앱 아이콘을 눌러 앱을 실행하게 되면 대략 사진과 같은 형태의 생명주기를 통해 메모리에 할당되었다가 소멸된다. 여기서 이번 글에 눈여겨볼 부분은 바로 UIApplicationMain() 호출 부분이다. swift이전에 obj-c로 작성되었던 앱은 c언어 기반이었기에 앱이 실행되면 운영체제가 가장 먼저 main.m 파일 안에 main() 함수를 호출하여 앱이 시작되었다고 한다.
swift가 c언어 기반은 아니지만 obj-c와 함께 사용되기 위한 언어여서인지, 동일하게 main() 함수를 호출을 해야하는데, 우선 xcode로 생성한 iOS 개발 템플릿에는 main.swift 파일은 보이지 않는다. 이유는 UIKit 프레임워크 안에 main() 함수를 숨겨놓았다고 한다. 따라서 앱이 실행되면 가장 먼저 운영체제가 개발자는 찾아볼 수 없는 main() 함수를 호출하고, main() 함수는 뒤이어 UIApplicationMain() 함수를 호출하여 UIApplication 객체가 생성이 되는 것이다. 그렇다면 UIApplication은 무엇일까?
The centralized point of control and coordination for apps running in iOS.
문서에 따르면 iOS에서 실행중인 앱의 제어와 조정을 담당하는 중앙지점이라고 적혀있다. 즉 여기서부터 실직적인 앱이라고 부를 수 있고, 해당 객체가 생성되고 나서야 개발자가 작성한 코드대로 이벤트 처리 등 앱의 동작을 제어할 수 있는 것이다.
모든 iOS앱은 단 하나의 UIApplication 인스턴스를 가지며, 개발자가 원한다면 UIApplication의 shared 프로퍼티를 통해 객체에 접근할 수 있다고 한다. 사실 무슨 말인지는 정확하게 와닿지 않아서 이 부분에 대해서는 나중에 시간을 들여 더 깊이 알아봐야겠다.
기본적인 유니온 파인드 문제다. 대신 문제에서 요구하는 것은 부품이 속한 컴포넌트의 크기이다.
풀이
부품의 번호가 1부터 1,000,000이기에 입력 인덱스를 바로 핸들링 하기 위해 1,000,001 개의 배열을 생성. 초기값을 -1로 둔다. 여기서 -1은 루트라는 것을 표시함과 동시에 컴포넌트의 개수를 음수로 표현하는 역할도 하게 된다.
파인드에 해당하는 root() 함수를 통해 배열의 값을 탐색, 값이 0보다 작으면 루트인 것으로 판정, 0보다 큰 값이면 해당 부품의 부모인 것으로 판정하고 부모의 루트를 재귀 호출하여 컴포넌트의 루트를 탐색한다.
유니온에 해당하는 union() 함수는 둘의 루트를 확인 후, 서로 다른 컴포넌트라면 합치는 과정을 수행하는데, 루트가 될 노드에 추가될 노드의 값을 더해주는 것으로 컴포넌트의 크기를 갱신하게 되고, 다른 컴포넌트로 편입하게 될 루트에는 해당 루트의 번호를 대입해주는 것으로 편입을 마치면 된다.
마지막으로 출력해야 할 경우에는 해당 부품의 루트를 찾고, 루트를 인덱스로 배열의 음수 값을 절댓값으로 출력해주면 된다.
실제로 스도쿠를 풀듯이 각 칸에 대한 숫자 대입 여부를 확인하면 된다. 그걸 어떻게 구현하느냐가 문제의 핵심. 결국 생각이 나지 않아 다른 분의 풀이에서 힌트를 얻고 문제를 풀었다.
스도쿠 판의 각 열, 행, 사각형에 1부터 9를 대입할 수 있는 2차원 배열을 생성한다. 입력받은 스도쿠 탐색 시 0을 마주하였을 경우 앞에서 생성한 3개의 배열에 대입하려는 숫자에 해당하는 인덱스가 모두 false인 경우, 숫자를 현재 좌표에 대입 후 재귀 호출, 해당 숫자가 답이 아닐 수 있으므로 0으로 복구시킨 후 다음 탐색을 수행한다.
애플리케이션을 설치할 때, 앱스토어와 운영체제가 디바이스의 환경에 맞게 설치하는 설치 최적화 기술이다.
필요한 만큼의 리소스만 다운로드하기에 적은 디스크 사용량, 빠른 다운로드를 제공한다.
해당 기술에는 slicing(슬라이싱), bitcode(비트 코드), on-demand resource(주문형 리소스)가 있다.
slicing
Slicing is the process of creating and delivering variants of the app bundle for different target devices and operating system versions.
슬라이싱은 여러 가지 디바이스와 운영체제를 위한 앱 번들의 variants(변형)을 생성 및 제공하는 과정을 뜻한다. variants(변형)에는 각 디바이스와 운영체제가 필요로 하는 실행 가능한 아키텍처와 리소스가 담겨있다고 한다. 개발자가 앱스토어 커넥트에 풀버전의 앱 빌드를 업로드하게 되면 앱스토어는 자동적으로 variants를 생성하고 전달한다고 한다.
유저가 앱스토어에서 앱을 다운로드하게 되면, 유저의 디바이스와 운영체제 버전에 맞는 variants를 다운로드하게 된다.
bitcode
Bitcode is an intermediate representation of a compiled program.
비트코드는 컴파일된 프로그램의 중간 표현이라고 한다. 즉, 기계 코드도 아니고, 프로그래밍 코드도 아닌 그 중간의 형태라고 보면 된다. 개발자는 앱스토어 커넥트에 자신의 앱에 비트 코드를 포함시켜 올릴 수 있으며 그러한 비트 코드는 컴파일되어 앱스토어에 연결된다. 애플은 업로드된 비트 코드를 통해서 개발자의 새로운 버전의 앱 업로드 없이도 앱 바이너리를 최적화할 수 있다고 한다.
*앱 바이너리 : 기계코드가 포함된 파일
자세한 부분까지 이해하기 쉽지 않으나, 본인이 보기엔 디바이스의 프로세서 아키텍처의 변경(32bit, 64bit)과 같은 부분에서 비트 코드가 없다면, 개발자가 새로 컴파일하여새로운 앱을 배포해야했으나, 기계어도, 프로그래밍 언어도 아닌 중간 형태의 비트 코드를 통해서 새로운 아키텍처의 변경에도 자동적으로 최적화가 이루어진다는 얘기 같다. 추가적인 정보는 더 찾아봐야 할 거 같다.
on-demand resource
On-demand resources are resources—such as images and sounds—that you can tag with keywords and request in groups, by tag.
주문형 리소스는 이미지, 음원과 같은 앱의 리소스를 키워드로 태그 해놓고, 태그를 통해 그룹으로 요청이 가능한 리소스다.
앱스토어는 사용자에게 현재 필요한 리소스를 관리하고 다운로드하게 한다. 또한 주문형 리소스의 슬라이싱 작업을 통해 variants의 최적화 작업을 진행한다고 한다. 이러한 주문형 리소스는 다음과 같은 이점을 제공한다.
앱의 사이즈가 작아지게 되고, 이를 통해 더 빠른 다운로드를 제공, 사용자가 앱의 최초 실행 경험을 개선하게 된다.
사용자가 앱을 체험하면서 필요하게 되는 주문형 리소스들을 백그라운드에서 다운로드하게 된다.
운영체제가 더 이상 필요로 하지 않는 주문형 리소스들은 제거하게 되고, 이로 인해 저장공간을 절약한다.
대표적인 예시를 들 수 있는 경우가 게임의 추가 리소스 다운이다. 일반적으로 이미지와 음원이 많은 게임 앱의 경우, 최초 실행을 위한 최소한의 리소스를 우선적으로 받고, 게임 실행 후 필요한 부분만 리소스를 추가적으로 다운로드하여 저장공간 절약, 실행을 위한 다운로드 시간 감소 등 대용량 앱 사용에 더욱 쾌적한 환경을 제공할 수 있다.