학사 나부랭이
iOS - Multitasking 본문
iOS는 정보보호와 안정적인 구동 환경을 위해 다방면으로 앱의 기능을 제한하죠. 백그라운드 프로세스 제약도 그중 하나예요.
왜 이런 백그라운드 프로세스에 제약을 뒀을까요? 먼저 보안을 위해서인데요. 일반 앱이 백그라운드에서 자유롭게 돌아갈 수 있다는 거는 악성 프로그램도 마찬가지로 무한으로 백그라운드 프로세싱을 즐긴다는 거죠. 그래서 허가된 조건 하에서만 백그라운드에서 작동할 수 있도록 해요. 그리고 자원을 아끼기 위해서 인데요. 무엇보다 스마트"폰"인데 백그라운드 프로세스로 인해서 전화받는 작업이 원활하지 못하면 본말전도라고 생각해서 제약을 둔 거 같아요.
그런데, 아이폰으로 카톡도 잘 되고, 음악도 잘 되는데 이건 어떻게 구현했을까요?
바로 멀티태스킹인데요, iOS4 이후부터 본격적으로 지원되었으며 PC의 멀티태스킹(멀티 프로그래밍)에 패스트 스위칭이 공존하는 개념이라고 보면 돼요. iOS7부터 모든 앱들에 대해 멀티태스킹을 지원하고 마찬가지로 앱 사용 유형과 시간을 분석해 자주 쓰는 앱이나 특정 시간대에 쓰는 앱은 미리 백그라운드에 로딩시켜주는 기능도 추가되었어요.
패스트 스위칭이 적용되는 경우, 홈 화면으로 가는 등 포어그라운드에서 벗어나면 앱이 Suspend되어 CPU나 배터리 소모를 하지 않는데, 포어그라운드를 벗어나기 직전의 상태가 Library/Caches/Snapshots에 저장되기에 아예 종료된 건 아닌 상태가 되어요. 그리고 배터리나 CPU는 소모하지 않는다만, 메모리는 차지하는데 그러니 메모리가 부족해지면 자동으로 종료 상태로 변환, 메모리 반납당할 수도 있어요.
여기서 아직 문제가 되는 점이 있는데, 하드웨어 제약에 따른 멀티태스킹의 제한이에요.
멀티태스킹 중 백그라운드 앱은 비활성화 상태로 진입하는데 이때, 패스트 스위칭을 지원하지 않으면 그냥 종료되는 것과 다름없어요. 그러니까 멀티 태스킹 앱의 개수가 3~4개로 제한되어 있는 거예요.
백그라운드 작업이 필요한 앱들은 백그라운드 작업 10분 연장해줘요. 그 10분이 지나고도 작업이 끝나지 않으면 또 10분 연장해주고... 그러다 작업이 끝나면 정지 상태가 되죠. 그리고 백그라운드에서 외부로부터 지속적인 업데이트가 필요한 음악, 카톡 등은 백그라운드에서 무기한 동작하도록 허용해줘요. 이는 멀티태스킹을 허용하면서 필수적인 백그라운드 작업만 허용함으로 불필요한 자원 사용, 충돌 등이 일어나지 않게 하기 위해서예요. 안드로이드 기기는 백그라운드 작업을 제한하지 않아 가끔 충돌이 나거나 구형 모델은 프리징으로 인해 전화를 못 받는 상황이 일어날 수도 있죠.
한 줄 요약하자면, 멀티태스킹을 지원하지 않고, 백그라운드 작업에 한해서 Suspend 상태, 10분 허용 상태를 줘서 불필요한 자원 소모를 막았다는 거예요.
그럼 이 백그라운드 모드를 어떻게 사용할까요?
백그라운드 모드의 지원 타입은 아래와 같아요.
Apple Push Notification (from network) Service & Local Notification (from device itself)
Task Completion
Background Audio (Audio Stream)
Background Location
VoIP (for calling, register the specific socket and monitor it)
Background Download (with silent notification)
프로젝트 파일 > target > Capabilities > Background Modes > 해당 항목 체크
위 처치를 적절히 하지 않으면 Reject 사유가 될 수 있어요.
UIBackgroundTaskIdentifier taskId; ///< 백그라운드 taskId
#pragma mark - background task
/**
백그라운드 시작을 알리는 함수
*/
- (void)startBackgroundTask
{
// System 에 background 작업이 필요함을 알림. 작업의 id 반환
taskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:taskId];
return ;
}];
}
/**
백그라운드 끝을 알리는 함수
*/
- (void)endBackgroundTask
{
[[UIApplication sharedApplication] endBackgroundTask:taskId];
taskId = 0;
}
//위와 같이 선언해 두고
[self startBackgroundTask];
// 할일
[self endBackgroundTask];
- (void)start
{
UIBackgroundTaskIdentifier newBgTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
if (bgTaskID != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:bgTaskID];
bgTaskID = UIBackgroundTaskInvalid;
}
}];
if (newBgTaskID != UIBackgroundTaskInvalid) {
[self stop];
bgTaskID = newBgTaskID;
}
}
- (void)stop
{
if (bgTaskID != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:bgTaskID];
bgTaskID = UIBackgroundTaskInvalid;
}
}
BackgroundTasks Framework - https://developer.apple.com/documentation/backgroundtasks
앱이 백그라운드에서 로딩(Fatch)될 수 있게 시스템에게 요청하는 것을 도와주는 프레임워크예요.
간단한 서버 호출과 업데이팅 작업부터 자원을 많이 소모하거나 네트워크 연결을 요구하는 작업도 요청할 수 있어요. 이 작업의 복잡도&자원 소모에 따라 두 가지 모드를 지원해요.
1. App refresh tasks
가벼운 작업, 단순 API 호출 및 저장, 사용자가 폰을 사용하고 있는 시간에도 실행시켜줘요.
2. Processing tasks
DB 등 크고 무거운 작업을 할 때 사용되어요. 옵션에서 추가적인 배터리를 사용하는가, 네트워크를 사용하는가 등의 요소도 지정할 수 있죠. 무거운 작업이기에 보통 충전 중이고 시스템이 idle 상태일 때 실행시켜줘요.
주의해야 할 건 일정한 시간에 호출되지 않는다는 거예요. 즉, 시스템이 판단했을 때, 배터리, 메모리 상황이 괜찮고, 사용자가 평소에 언제 앱을 켜는지 학습해 그전에 호출해줘요. 그리고 사용자가 일주일 이상 앱을 실행하지 않으면 더 이상 로딩도 실행되지 않아요. 그리고 메인 스레드가 아니기에 UI 조작을 하게 되면 메인 스레드가 아니기에 크래시가 나요.
적용법은 여기서 보세요. https://lemon-dev.tistory.com/entry/iOS-BackgroundTask-Framework-%EA%B0%84%EB%8B%A8-%EC%A0%95%EB%A6%AC
'自習 > iOS' 카테고리의 다른 글
iOS - How to Break the Sandbox (0) | 2021.06.03 |
---|---|
iOS - Code Signing, Certification, Provisioning Profile (0) | 2021.06.03 |
iOS - Sandbox, Container Directory (0) | 2021.06.03 |