어느 개발자의 한적한 공간 살아나가면서 저지른 이야기

애플리케이션 생명 주기

  • 미실행 상태
    • 기기를 새로 부팅한 후 모든 앱이 속하는 상태이다.
    • Info.plist (값이 YES로 설정된) UIApplicationExitsOnSuspend 키가 들어 있는 경우
    • 어플리케이션이 이전에 실행 중단되었고 시스템에서 일부 메모리를 제거하는 경우
    • 어플리케이션이 실행 도중 충돌로 인해 종료한 경우
  • 활성 상태
    • 어플리케이션이 화면에 보이고 어플리케이션이 실행되는 정상 상태다. 사용자의 입력을 받고 디스플레이를 업데이트할 수 있다.
  • 백그라운드 상태
    • 일부 코드를 실행할 수 있는 시간이 어플리케이션에 주어지지만, 어플리케이션이 화면에 직접 접근하거나 사용자 입력을 받을 수는 없다. 모든 어플리케이션은 사용자가 홈 버튼을 누를 때 짧게 이 상태로 들어간다. 대부분의 어플리케이션은 이후 바로 실행 중단 상태로 들어간다. 백그라운드에서 실행돼야 하는 어플리케이션은 다시 활성 상태로 돌아가기 전까지 이 상태에 머문다.
  • 실행 중단 상태
    • 일반적인 어플리케이션이 백그라운드 상태를 잠깐 거친 후 전환되는 상태다. 어플리케이션이 활성 상태일 때 사용한 메모리는 이 상태에서 모두 그대로 유지된다. 사용자가 다시 어플리케이션을 활성 상태로 만들면 어플리케이션은 이전의 상태를 바로 회복한다. 하지만 현재 활성화된 앱으로 인해 시스템에서 추가 메모리가 필요하면 실행 중단된 앱은 강제 종료될 수 있으며 (더불어 미실행 상태에 놓인다) 다른 앱에서 사용할 수 있게 메모리에서 제거될 수도 있다.
  • 비활성 상태
    • 어플리케이션은 다른 두 상태 사이에서 전환하는 짧은 기간 동안만 비활성 상태에 놓인다. 어플리케이션이 오랫동안 비활성 상태에 머물 수 있는 경우는 사용자가 시스템 프롬프트(전화나 문자 메세지가 오는 등)를 처리하거나 사용자가 화면을 잠근 경우뿐이다. 이 상태는 기본적으로 일종의 림보 상태라 할 수 있다.

상태 변화 알림

  • didFinishLaunchingWithOptions: - 어플리케이션이 구동을 마친 직후 어플리케이션 수준의 코딩을 할 때 주로 사용하는 메서드
  • applicationWillResignActive: - 사용자가 홈버튼을 누르면 호출 ; 메서드가 호출된다고 해서 어플리케이션이 백그라운드로 들어간다고 가정할 수 없다는 점에 주의! 이 상황에 잠깐 머물다가 다시 어플리케이션이 바로 활성 상태로 바뀔 수도 있기 때문이다.
  • applicationDidBecomeActive: - 다시 어플리케이션이 전방으로 나올때 호출,
    • 이들 쌍은 어플리케이션이 활성 상태에서 비활성 상태로 전환될 때의 움직임을 나타내고, 애니메이션, 어플리케이션 내의 오디오 재생, 기타 어플리케이션 이 사용자에게 보일 때 처리해야 하는 항목들을 활성화하거나 비활성화하는 데 주로 사용한다.
  • applicationDidEnterBackground: - 나중에 재생성할 수 있는 모든 리소스를 제거하고 사용자 데이터를 저장한 후 네트워크 연결을 닫는 등의 작업을 수행하는 메서드다. 필요하다면 어플리케이션이 백그라운드에서 실행될 수 있게 시스템에 추가 시간을 요구하는 코드를 작성하는 데 사용할 수 있다. 메서드가 호출될 때는 그 전에 항상 applicationWillResignActive: 메서드도 호출 됐음을 확신할 수 있다는 점을 기억할 것.
  • applicationWillEnterForeground: - 마찬가지로 applicationWillEnterForeground:가 호출될 때는 applicationDidBecomeActive:도 잠시 후 호출될 것임을 알 수 있다.
    • 어플리케이션이 백그라운드로 확실히 보내질 때 이를 처리한다.
    • 사용자 데이터를 재로드하거나 네트워크 연결을 재개하는 등 applicationDidEnterBackground:에서 제거한 리소스를 재생성하려면 applicationWillEnterForeground:메서드를 구현해야한다.
  • applicationWillTerminate: -

실행 상태 변화의 활용

  • 활성 -> 비활성 상태로의 전환
    • 이 때는 applicationWillResignActive:/UIApplicationWillResignActiveNotification을 활용해 어플리케이션의 디스플레이를 ‘일시정지한다.’
  • 비활성 -> 백그라운드 상태로의 전환
    • applicationDidEnterBackground:/UIApplicationDidEnterBackgroundNotification을 활용해 어플리케이션이 백그라운드에 있는 동안 갖고 있을 필요가 없는 리소스(캐시 이미지나 쉽게 재로드할 수 있는 데이터 등) 또는 백그라운드에서 유지할 수 없는 리소스(활성화된 네트워크 연결 등)를 모두 릴리즈한다. 이때 이런 추가 메모리 사용 부분을 제거하면 어플리케이션의 실행 중단 상태에서 어플리케이션의 스냅샷 규모가 작아지고 어플리케이션이 램에서 완전히 제거될 확률이 그만큼 낮아진다. 또 이때는 다음 번에 어플리케이션이 재구동될 때 좀 더 쉽게 이전 상태로 복원될 수 있게끔 어플리케이션 데이터를 저장할 수도 있다. 어플리케이션이 다시 활성 상태로 돌아온다면 이 부분은 문제가 되지 않지만 어플리케이션을 종료한 후 재실행할 때 사용자가 이전 사용 시점에서 그대로 어플리케이션을 사용할 수 있다면 이를 통해 사용자를 그만큼 배려할 수 있다.
  • 백그라운드 -> 비활성 상태로의 전환
    • applicationWillEnterForeground:/UIApplicationWillEnterForeground를 활용해 비활성 상태에서 백그라운드 상태로 전환할 때 한 작업을 모두 언두(undo)한다. 예를 들어 이때는 네트워크 연결을 재설정할 수 있다.
  • 비활성 -> 활성 상태로의 전환
    • applicationDidBecomeActive:/UIApplicationDidBecomeActive를 활용해 활성 상태에서 비활성 상태로 전환할 때 한 작업을 모두 언두(undo)한다. 하지만 어플리케이션이 게임이라면 이 상태에서 바로 게임 실행을 재개해서는 안 된다. 게임 실행 재개는 사용자들이 스스로 할 수 있게 해야 한다. 또한 이 메서드 및 알림은 어플리케이션이 새롭게 실행될 때도 사용됨을 주의해야한다. 따라서 여기서 실행하는 코드는 이런 상황에서도 적절한 코드여야 한다.
  • 비활성 -> 백그라운드 상태로의 전환은 별도로 고려해야 한다. 이 상태 전환에 사용되는 메서드와 알림은 앞의 목록에서 이름이 가장 길 뿐 아니라 어플리케이션에서 추적해야하는 작업량으로 인해 아마도 가장 많은 코드를 사용하고 가장많은 시간을 요하는 전환을 처리한다. 이 전환이 진행될 때는 시스템에서 변경 사항을 저장할 수 있게 무한정의 시간을 어플리케이션에게 제공하지 않는다. 다만 5초 정도의 시간만을 주고 어플리케이션이 델리게이트 메서드에서 이 시간 내에 결과를 반환하지 않으면(아울러 등록한 알림을 모두 처리하지 않으면) 어플리케이션이 메모리에서 강제 제거되고 미실행 상태에 놓인다. 이런 처사가 불공평하다고 생각한다면 이런 처리를 유예할 수 있기 때문에 걱정이 없다. 델리게이트 메서드나 알림을 처리할 때는 시스템에게 백그라운드 큐에서 추가 작업을 처리할 수 있게 해달라고 요청하면 추가 시간을 더 벌 수 있다.

비활성 상태 처리

- (void)rotateLabelUp {
  [UIViewanimateWithDuration:0.5 animations:^{
    _label.transform = CGAffineTransformMakeRotation(0);
  } completion:^(BOOL finished){
    [selfrotateLabelDown];
  }];
}

- (void)rotateLabelDown {
  [UIViewanimateWithDuration:0.5 animations:^{
    _label.transform = CGAffineTransformMakeRotation(M_PI);
  } completion:^(BOOL finished){
    [selfrotateLabelUp];
  }];
}
  • UIView는 애니메이션을 설정하는 animateWithDuration:animations:completion:이라는 클래스 메서드를 정의한다. 애니메이션 블록 내에서 선언한 애니메이션 적용 가능 속성들은 효과를 바로 적용하지 않는다. 대신 코어 애니메이션은 속성의 현재 값을 지정한 새로운 값으로 부드럽게 전환한다. 이를 암시작 애니메이션이라 부르는데, 이 기능은 코어 애니메이션의 주요 기능 중 하나다. 마지막에 있는 competion 블록은 애니메이션이 종료된 후 실행할 내용을 지정할 수 있게 해준다.
  • 이제 이들 메서드는 라벨의 transform 속성을 라디언으로 지정한 특정 회전값으로 설정한다. 두 메서드는 모두 completion 블록을 설정해 다른 메서드를 호출함으로써 텍스트가 계속해서 앞뒤로 애니메이션 되게 한다.
  • 끝으로 애니메이션을 시작할 수 있는 방법을 설정해야 한다. 여기에서는 다음 코드를 viewDidLoad 메서드 끝에 추가해 이를 처리한다.

앱이 실행 중단된 상태에서 더 적은 리소스를 사용할수록 iOS에서 앱을 완전히 종료할 가능성도 그만큼 줄어든다는 앞의 설명을 기억할 것!

  • 백그라운드 처리를 위해 applicationDidEnterBackground 함수에서 내용을 저장한다.
  • 다시 불러올때는 앱은 이미 실행중이기 때문에 viewDidLoad 메서드를 사용하여 정보에 접근한다.

iOS 개발 #iOS