Hi yoahn 개발블로그

[Swift] #2 iOS 앱의 구조와 코코아 터치 프레임워크 본문

프로그래밍 언어/swift

[Swift] #2 iOS 앱의 구조와 코코아 터치 프레임워크

hi._.0seon 2020. 12. 16. 15:01
반응형

2.1 앱의 기본 구조

2.1.1. 엔트리 포인트와 앱의 초기화 과정

C언어에 뿌리를 둔 모든 애플리케이션은 main() 함수로부터 시작된다. (=엔트리 포인트) 오브젝티브-C 역시 C언어에 기반, 오브젝티브-C 도 main( ) 함수로부터 시작됨

운영체제가 애플리케이션 내부에 정의된 main() 함수를 찾아 호출하면 코드들이 연쇄적으로 실행됨

 

Xcode 프로젝트를 생성하면 main( ) 함수가 자동으로 만들어지는데 iOS 앱이 실행될 때 처리할 내용이 적혀있으므로 건드릴 필요 없음

 

#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 프레임워크에 속해있으므로 이후 앱 제어권은 UIKit 프레입워크로 이관됨

 

UIApplicationMain( ) 함수

: iOS 앱에 속하는 부분의 엔트리 포인트

- 앱의 핵심 객체를 생성하는 프로세스를 핸들링

- 스토리보드 파일 -> 앱의 유저 인터페이스를 읽어들임 & 커스텀 코드 호출 -> 앱 생성 초기에 필요한 설정 구현

- 이벤트 루프 실행 <- 이벤트를 입력받기 위함

 

- UIApplication을 생성

: 앱의 본체라고 할 수 있는 객체 (앱 그 자체)

- 커스텀 코드, 객체, 앱의 기능 모두 UIApplication에 포함되어 있는 하위 객체

- 모바일 디바이스에 설치된 앱을 실행하면 초기 구동 과정을 거쳐 앱 프로세스가 메모리에 등록되는데, 이때의 앱 프로세스가 곧 UIApplication 객체라고 보아도 됨

 

UIApplication 객체의 역할

- 이벤트 루프, 다른 높은 수준의 앱 동작을 관리

- 푸시 알림과 같은 특수한 이벤트를 커스텀 객체 (Delegate)에게 알려주기도 한다.

= 이 클래스는 보통 서브클래싱 없이 그대로 사용

-> 서브 클래싱이 필요한 경우 UIApplication 객체는 AppDelegate라는 대리 객체를 내세우고 커스텀 코드를 처리할 수 있도록 약간의 권한을 부여

AppDelegate 객체

- iOS 애플리케이션 내에서 오직 하나의 인스턴스만 생성되도록 시스템적으로 보장받는다.

- 앱 전체의 생명 주기와 함께 함

=> AppDelegate 객체에 데이터를 저장하면 앱이 종료될 때까지 계속 데이터를 유지할 수 있다

-> 앱의 초기 데이터 구조를 설정하기 위해 사용되기도 한다.

 

UIApplication 객체와 AppDelegate 객체가 연관되어 앱이 실행되는 전체 과정

1. main( ) 함수 실행

2. main( ) 함수는 다시 UIApplicationMain( ) 함수를 호출

3. UIApplicationMain( ) 함수는 앱의 본체에 해당하는 UIApplication 객체를 생성한다.

4. UIApplication 객체는 Info.plist 파일을 바탕으로 앱에 필요한 데이터와 객체 로드

5. AppDelegate 객체를 생성하고 UIApplication 객체와 연결

6. 이벤트 루프 만드는 등 실행에 필요한 준비

7. 실행 완료 직전, AppDelegate의 application(_:didFinishLaunchingWithOptions:) 메소드를 호출

 

But, Swift는 C 기반의 언어가 아님. 스위프트 기반 프로젝트에는 main.m 파일이 존재하지 않으며 엔트리 포인트 역시 존재하지 않음

=> 스위프트에서는 위의 1 - 5 과정을 @UIApplicationMain 이라는 어노테이션 표기로 대체

 

- 스위프트에서는 AppDelegate 역할을 할 클래스에 @UIApplicationMain 어노테이션을 걸어 표시하는 방식으로 시스템에 델리게이트 클래스 정보를 전달

- iOS 시스템은 앱을 실행할 때 이 어노테이션이 표시된 클래스를 찾아 델리게이트로 지정하게 됨

- 시스템 프레임워크 -> 사용자가 앱 아이콘을 탭하면 앱을 구동

- @UIApplicationMain 어노테이션을 찾아 해당 클래스를 실행

- 커스텀 코드 > 앱 델리게이트 클래스에 작성된 application(_:didFinishLaunchingWithOptions:) 메소드가 시스템에 의해 자동으로 호출

- 시스템 프레임워크의 이벤트 루프가 실행됨

 -> 작성된 이벤트 핸들에 의해 커스텀 코드로 연결됨

(이벤트 루프에서는 특정 이벤트가 발생했을 때 우리가 만든 핸들을 통해 커스텀 코드를 실행할 수 있도록 처리 <ex. @IBAction..)

 

- 앱이 실행 목적을 모두 완료, 더이상 사용되지 않으면 시스템은 앱ㄷ을 메모리에서 제거하기 위한 준비

- 앱 시스템 -> 앱 델리게이트 클래스의 applicationWillTerminate(_:) 메소드를 호출

(앱이 곧 종료될 테니 정리할 것이 있으면 처리할 내용이 있으면 코드를 작성하세요)

 

앱 델리게이트 프로토콜에는 더 많은 메소드가 있음. 각 메소드는 미리 약속된 시점에 맞추어 시스템에 의해 호출될 수 있도록 구성되어 있다.

 

2.1.2. MVC 패턴

iOS 앱의 객체 관계 = MVC 패턴

: 소스 코드 설계 기법

Model - View - Controller 

- 모델: 데이터 담당

- 뷰: 데이터에 대한 화면 표현 담당

- 컨트롤러: 모델 - 뷰 사이에 위치, 데이터를 가공하여 뷰로 전달, 뷰에서 발생한 이벤트를 입력받아 처리하는 역할 담당

iOS의 MVC 패턴 영역별 객체들과 상호작용 관계

각각의 역할로 쪼개고 나누어 놓은 이유

# 패턴의 장점

1. 데이터와 비즈니스 로직을 시각적인 표현으로부터 분리, 화면을 신경쓰지 않고 (데이터, 비즈니스) 로직 작성이 가능

- 데이터 관리, 기능 구현, 화면 표현 부분들이 한 곳에 모여 있게 되면, 화면 크기가 달라지는 경우 데이터 & 비즈니스 로직에 화면 구성 부분이 섞여 있기 때문에 화면을 어떻게 구성할지에 대한 내용이 달라지면 연관된 모든 소스코드의 수정이 필요해진다.

하지만 데이터 관리나 기능 구현 부분이 바뀌어야 하는 것은 아니므로 어떻게 보여지느냐에 대한 차이만 제외하면 나머지는 변하지 않는 부분이다. 또한 기능 구현 부분이 변경된다고 해서 화면 표현 부분, 데이터 가져오는 부분에 대한 코드는 건드릴 필요가 없다.

 

이런 관점에서 출발한 것이 MVC 패턴이다. 프로그램을 특성에 따라 서로 영향을 미치지 않는 범위로 분리해 놓은 것이다. 어느 한 부분의 코드를 수정한다고 해서 다른 부분에 영향을 미치지 않으므로 프로그램이 유연해지는 결과를 얻을 수 있게 된다.

 

2.1.3. 앱의 상태 변화

- 운영체제가 처리하는 영역

Not Running 앱이 시작되지 않았거나 실행되었지만 시스템에 의해 종료된 상태
Inactive 앱이 전면에서 실행 중이지만, 아무런 이벤트를 받지 않고 있는 상태
Active 앱이 전면에서 실행 중, 이벤트를 받고 있는 상태
Background 앱이 백그라운드에 있지만 여전히 코드가 실행되고 있는 상태.
대부분의 앱은 Suspended 상태로 이행하는 도중에 일시적으로 이 상태에 진입하지만, 파일 다운로드나 업로드, 연산처리 등 여분의 실행 시간이 필요한 앱일 경우 특정 시간 동안 이 상태로 남아있게 되는 경우도 있다.
Suspended 앱이 메모리에 유지되지만 실행되는 코드가 없는 상태
메모리가 부족한 상황이 되면 iOS 시스템은 포그라운드에 있는 앱의 여유 메모리 공간을 확보하기 위해 Suspended 상태에 있는 앱들을 특별한 알림 없이 정리한다.

iOS 앱의 생명주기

어떤 특정한 순간에 앱은 위 5가지 상태 중 하나일 수도 있고, 다른 상태로 옮겨가는 중일수도 있다.

하나의 상태에서 다른 상태로 옮겨가는 중 == 상태 변화

 

앱의 실행 상태가 변화할 때마다 앱 객체는 앱 델리게이트에 정의된 특정 메소드를 호출

(앱 종료 전에 데이터 저장, 백그라운드인 경우 필요없는 메모리 정리)

앱 델리게이트 객체에 다양한 메소드들이 정의되어 있고, 각 메소드들은 모두 그에 맞는 상태 변화에 따라 호출된다.

 

# application(_:willFinishLaunchingWithOptions:)

- 앱이 구동되어 필요한 초기 실행 과정이 완료되기 직전에 호출되는 메소드

 

# application(_:didFinishLaunchingWithOptions:)

- 앱이 사용자에게 화면으로 표시되기 직전에 호출되는 메소드. 앱이 실행된 후에 진행할 커스터마이징이나 초기화를 위한 코드 작성

 

# applicationDidBecomeActive(_:)

- 실행된 앱이 포그라운드 (화면 전면)에 표시될 때 호출되는 메소드. 앱이 Inactive 상태에 들어가면서 일시 중지된 작업이 있다면 이를 재시작하는 코드를 여기에 작성해 주어야 한다.

(타이머 | 스톱워치의 경우, Inactive 상태로 들어가면 더 이상 화면 갱신이 이루어지지 않고 예전 화면이 유지되므로 이 메소드를 통해 화면과 남은 시각 등을 갱신)

 

# applicationDidEnterBackground(_:)

- 앱이 백그라운드 상태에 진입했을 때 호출된다. 이 메소드가 호출된다는 것은 미래의 어느 순간 앱이 종료된다는 것. 중요한 데이터를 종료 전에 미리 저장하거나, 공유 자원을 점유하고 있는 경우는 해제시켜 주어야 함

- 종료된 앱이 다시 실행될 때 현재의 상태를 복구할 수 있도록 필요한 상태 정보도 이 메소드에서 저장해두는 것이 좋다.

 

# applicationWillTerminate(_:)

- 앱이 종료되기 직전 호출되는 메소드. 사용자 데이터 등을 종료 전에 한 번 더 저장해 두는 것이 좋다.

 

이외에도 다양한 메소드가 존재. UIAppDelegateProtocol 공식 문서 참고

 

2.2 iOS와 코코아 터치 프레임워크

Swift 언어는 앱을 만들 수 있는 기술이 전혀 없다. iOS 용 앱을 만드는 방법은 프레임워크안에 담겨있다. 파운데이션 프레임워크나 UIKit 프레임워크, 웹킷 프레임워크 등의 계층을 거슬러 올라가면 코코아터치라는 하나의 거대한 프레임워크가 나온다. 앱을 만들고 실행할 때 필요한 iOS 기반 기술들은 모두 코코아 터치 프레임워크를 통해 구현되기 때문에, 앱을 제작하기 위해서는 결국 코코아 터치 프레임워크 전체를 이해해야 한다.

 

# 프레임워크

- 어떤 것을 이루는 뼈대, 기본 구조

- 애플리케이션 제작을 빠르고 편리하게 할 수 있도록 미리 뼈대를 이루는 각종 코드를 제작하여 모아둔 것

2.2.1 iOS

애플이 개발해서 제공하는 임베디드 운영체제.

- 기본적으로 하나의 홈 스크린을 사용

 홈 스크린에는 현재 실행되고 있는 앱이 표시됨. 새로운 앱을 실행하면 기존의 앱이 홈 스크린에서 비켜나고 새로운 앱이 그 자리를 채우는 방식으로 동작한다.

-> 최근 홈 스크린을 분할하여 여러 앱을 동시에 나타내는 기능이 확장되었지만 아이패드 같은 일부 디바이스에서만 허용되고 하나의 화면을 분할해서 사용하는 것이기 때문에 일반 컴퓨터 방식과는 차이가 있다.

 

iOS에서 제공하는 SDK는 기기의 홈 스크린에 표현될 네이티브 앱을 개발하고 설치하여 실행하고 테스트하는 데 필요한 도구와 화면을 모두 포함하고 있다. SDK 가 없으면 네이티브 앱을 개발할 수 없고, 테스트 & 실행해볼 수도 없다. SDK가 제공되지 않으면 특정 OS 에서 동작하는 앱 만드는 것을 허용하지 않는다는 것이다.

 

 

 

반응형
Comments