앱의 기본 구조
iOS 애플리케이션은 Custom Code와 System Framework로 나뉘어져 있다.
Custome Code는 우리가 직접 작성하는 코드, System Framework는 기반 환경이며 개발자가 건드릴 수 없는 영역이다.
C 언어에 뿌리를 둔 모든 애플리케이션은 main() 함수로부터 시작된다. 이를 Entry Point라 하는데 Objective-C로 만들어진 iOS 애플리케이션도 C언어 기반이므로 main() 함수로부터 시작된다.
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char* argv[]){
@autoreleasepool{
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
main() 함수가 하는 일은 실행 시 시스템으로부터 전달받은 두 개의 인자 값과 AppDelegate 클래스를 이용하여 UIApplicationMain()함수를 호출하고 그 결과로 UIApplication 객체를 반환한다. UIApplication 객체는 UIKit Framework에 속해있으므로 이후의 앱 제어권은 UIKit Framework로 이관된다.
C 기반 애플리케이션의 엔트리 포인트가 main() 이라면, iOS 앱의 엔트리 포인트는 UIApplicationMain()이라 할 수 있다. 이 함수는 앱의 핵심 객체를 생성하는 프로세스를 핸들링하고 스토리보드 파일로부터 앱의 UI를 읽어들일뿐만 아니라, 커스텀 코드를 호출해 줌으로써 앱 생성 초기에 필요한 설정을 구현할 수 있게 한다. 이 과정에서 우리가 직접 구현해야 할 것은 스토리보드 파일이나 초기화를 위한 Custom Code이다.
UIApplicationMain()이 생성하는 UIApplication 객체는 사실상 앱의 본체이다. 우리가 작성한 Custom Code나 객체, 앱의 기능 등은 모두 UIApplication에 포함되어 있는 하위 객체이다. 앱을 실행하게 되면 초기 구동 과정을 거쳐 앱 프로세스가 메모리에 등록되는데, 이 때의 앱 프로세스가 곧 UIApplication 객체이다.
UIApplication 객체는 이벤트 루프와 같은 앱 동작을 관리할 뿐만 아니라 푸시 알림과 같은 특수 이벤트를 우리가 정의한 Custom Object인 Delegate에 알려주기도 한다. 이 클래스는 거의 Subclassing하지 않고 사용하는데, 이는 한계가 있다. 따라서 우리는 AppDelegate라는 대리인을 통해 Custom Code를 처리할 수 있도록 권한을 부여한다.
iOS 애플리케이션 프로젝트를 생성하면 AppDelegate.swift라는 파일을 볼 수 있을 것이다.
그 안에 다음과 같이 손쉽게 Custome Code를 작성할 수 있다.
아래의 코드는 시작 화면 노출 시간을 3초간 지연시킨 코드이다.
AppDelegate 객체는 iOS 애플리케이션 내에서 오직 하나의 인스턴스만 생성되도록 보장받는다. 또한, 앱이 처음 만들어질 때 객체가 생성, 종료되면 함께 소멸하는 등 앱 전체의 생명주기와 함께 한다. 이러한 특성 때문에 AppDelegate 객체에 데이터를 저장하면 앱이 종료될 때까지 계속 데이터를 유지할 수 있다. 따라서, AppDelegate 객체는 종종 앱의 초기 데이터 구조를 설정하기 위해 사용되기도 한다.
만약 Objective-C가 아닌 Swift로 쓰여진 프로젝트는 어떨까? Swift는 C언어 기반이 아니다.
따라서, Swift 기반 프로젝트에는 main() 함수가 존재하지 않고 어노테이션 표기(@UIApplicationMain)로 대체한다.
Swift에서는 직접 UIApplicationMain()을 호출하여 Delegate Class를 인자값으로 전달할 수 없으므로 대신 AppDelegate 역할을 할 클래스에 어노테이션을 걸어 시스템에 Delegate Class 정보를 전달한다. iOS 시스템은 이 어노테이션이 표시된 클래스를 찾아 Delegate로 지정하게 된다. 이후의 과정은 앞선 설명과 동일하다.
MVC 패턴
iOS 앱의 객체 관계는 MVC 패턴에 기반하고 있다. MVC 패턴이란 Model - View - Controller의 3개의 핵심 구조를 이용하여 애플리케이션을 설계하는 것을 말한다. Model은 데이터를 담당하고, View는 데이터에 대한 화면 표현을 담당하며, Controllers는 Model과 View 사이에 위치하여 데이터를 가공하여 View로 전달하고, View에서 발생하는 이벤트를 받아 처리하는 역할을 담당한다.
MVC 패턴의 장점은 데이터와 비즈니스 로직을 시각적 요소들로부터 분리해줌으로써 화면을 신경쓰지 않아도 된다는 것이다.
예를 들어, iOS, watchOS 등에서는 화면의 크기가 다르기 때문에 전체 프로그램을 새로 작성해야 한다. 하지만, MVC 패턴은 이러한 영향을 받지 않으므로 훨씬 프로그램이 더 유연해질 수 있게 한다.
앱의 상태 변화
앱은 실행되는 동안 시작, 백그라운드 상태, 실행, 종료 등 다양한 상태로 변화한다. 이러한 앱의 상태 변화는 iOS에서 처리한다.
예를 들어, 앱을 사용하는 도중 전화가 오면 앱은 화면에서 사라지고 전화 화면을 사용하게 된다. 통화가 종료되면 iOS는 다시 기존의 앱을 화면에 나타나게 만든다. iOS에서 앱이 가질 수 있는 상태는 다음과 같다.
- Not Running : 앱이 시작되지 않았거나 실행되었지만 시스템에 의해 종료된 상태.
- Inactive : 앱이 전면에서 실행 중이지만, 아무런 이벤트를 받고 있지 않는 상태.
- Active : 앱이 전면에서 실행 중이며, 이벤트를 받고 있는 상태.
- Background : 앱이 백그라운드에 존재하며 여전히 코드가 실행되고 있는 상태. 대부분의 앱이 Suspended 상태로 가는 도중 일시적으로 이 상태에 진입한다. 파일 다운로드, 업로드, 연산 처리 등의 실행 시간이 필요한 앱의 경우 특정 시간동안 이 상태로 남아있는다.
- Suspended : 앱이 메모리에 유지되지만 실행되는 코드는 없는 상태. 메모리가 부족한 경우 Suspended 상태의 앱들을 특별한 알림 없이 정리한다.
앱의 생명 주기(Life Cycle)은 다음 그림과 같다.
앱의 실행 상태가 변화할 때마다 앱 객체는 App Delegate에 정의된 특정 메소드를 호출한다. 우리는 이 메소드 내부에 적절한 Custom Code를 작성하여 원하는 작업이 실행되도록 할 수 있다. 아래는 주요 메소드들이다.
- application(_:willFinishLaunchingWithOptions:)
앱이 구동되어 필요한 초기 실행 과정이 완료되기 직전에 호출되는 메소드
- application(_:didFinishLaunchingWithOptions:)
앱이 사용자에게 화면으로 표시되기 직전에 호출되는 메소드. 초기화 등의 작업에 사용됨.
- applicationDidBecomeActive(_:)
실행된 앱이 포그라운드에 표시될 때 호출되는 메소드. 앱이 Inactive 상태로 변하며 일시 중지된 작업이 있다면, 이 메소드에 재시작 코드를 작성해야 한다. 예를 들어, 스톱워치 앱의 경우 Inactive 상태가 되면 더 이상 화면 갱신이 이루어지지 않고 예전 화면이 유지되므로 화면과 남은 시간 등을 갱신해야한다.
- applicationDidEnterBackground(_:)
앱이 백그라운드 상태에 진입했을 때 호출되는 메소드. 백그라운드 상태에 진입했다는 의미는 미래의 어느 순간 앱이 종료될 수 있다는 의미이므로 중요한 사용자 데이터를 미리 저장하거나 점유하고 있는 공유 자원을 해제해주어야 한다. 다시 앱이 실행될 때 현재의 상태를 복구할 수 있도록 필요한 상태 정보도 저장해놓는 것이 좋다.
- applicationWillTerminate(_:)
앱이 종료되기 직전에 호출되는 메소드. 사용자 데이터 등을 종료 전에 한 번 더 저장해두는 것이 좋다.
이 외에도 다양한 상태 변화에 대응하기 위한 메소드들이 있다.
*이 포스트는 꼼꼼한 재은씨의 Swift:기본편을 토대로 작성되었습니다.
'앱 > iOS' 카테고리의 다른 글
Swift - 모나드 (0) | 2022.01.22 |
---|---|
Swift의 연산자 (0) | 2022.01.13 |
iOS - 객체 제어 (0) | 2021.11.07 |
iOS와 코코아 터치 프레임워크 (0) | 2021.11.06 |
첫 iOS 앱 클론코딩 후기 (0) | 2021.02.10 |