[iOS] NotificationCenter

팔랑이·2024년 5월 22일

iOS/Swift

목록 보기
22/81
post-thumbnail

NotificationCenter는 iOS에서 런타임 이벤트를 감지하고 처리하기 위한 기능이다.

프로젝트에 사용했던 위치 정보 업데이트 기능 기반으로 설명
(사용자가 지도 움직임 -> 위치정보 업데이트하여 정렬 다시)

Notification과 NotificationCenter

Notification

: 특정 이벤트나 상태 변화를 나타내는 객체. 주로 이름, 객체, 사용자 정보 딕셔너리로 구성

name: 노티피케이션의 이름. 식별자 역할을 함.
object: 이벤트를 발생시킨 객체. 옵셔널.
userInfo: 추가 정보를 담은 딕셔너리. 옵셔널.

NotificationCenter

: 노티피케이션을 관리하고, 옵저버들에게 전달하는 싱글톤 객체.

addObserver: 옵저버를 등록하고, 특정 노티피케이션을 받을 메소드를 지정.
post: 노티피케이션을 발생시키고, 등록된 옵저버들에게 전달.
removeObserver: 옵저버를 제거.

전체적인 흐름
1.viewDidLoad() 에 옵저버 등록, 이벤트 감지 메서드 설정
2. 이벤트 발생시 NotificationCenter에 노티피케이션 전송
3. NotificationCenter는 해당 노티피케이션을 전 옵저버에 전달
4. 옵저버는 전달받은 메서드를 처리

기본 구조

1. 옵저버 등록

NotificationCenter.default.addObserver(self, selector: #selector(updateLocation), name: .locationDidUpdate, object: nil)
  • NotificationCenter.default: 싱글톤 객체'
  • .addObserver 메서드로 updateLocation을 옵저버로 등록하여 대기시킴
  • .locationDidUpdate 노티피케이션 발생시 등록된 updateLocation 메서드 호출

참고 - selector: obj-c와의 호환성을 위해 사용. 클로저 기반으로 바꿔서 사용할 수도 있으나, NotificationCenter 자체가 obj-c 기반이라 여전히 selector를 자주 사용. 이에 대해서는 추후 더 자세히 다룰 예정

2. 이벤트 발생

func postLocationUpdate(location: CLLocation) {
    NotificationCenter.default.post(name: .locationDidUpdate, object: nil, userInfo: ["location": location])
}
  • 이벤트 발생시 .post 메서드로 노티피케이션을 보냄
  • object, userInfo에 들어가는 정보를 함께 노티피케이션 센터로 전달
  • object: 특정 객체에 대해서만 노티피케이션을 받으려면 설정. 보통은 nil로 설정해서 모든 객체의 노티피케이션을 받음.object: someObject로 설정하면 someObject가 보내는 객체의 노티피케이션만 받는다.
  • userInfo: 딕셔너리 형태로 필요한 정보를 전달, [AnyHashable: Any] 타입의 딕셔너리.

3. 이벤트 전달

  • NotificationCenter는 옵저버들에 .locationDidupdate 노티피케이션을 전달

4. 이벤트 처리

@objc func updateLocation(notification: Notification) {
    if let location = notification.userInfo?["location"] as? CLLocation {
        currentLocation = location
        updateMapRegion(location: location)
        updateTableViewSorting()
    }
}

함수 설명

  • userInfo로 받아오는 딕셔너리는 [AnyHashable: Any] 타입으로, 여기서는 location 키에 해당하는 값을 가져온다.

  • as? 타입 변환을 이용해 딕셔너리에서 가져온 값의 타입 Any를 변환, 여기서는 CLLocation 타입의 옵셔널로 변환한다. 변환이 실패할 경우 nil을 반환.

  • 변환이 성공, 즉 옵셔널 값이 nil이 아니면 이후 코드가 실행된다.

    참고: as?는 타입을 안전하게 변환하는 연산자. 캐스팅이 성공하면 해당 타입의 옵셔널 값을 반환하고, 실패하면 nil을 반환하기 때문에 런타임 오류를 방지할 수 있다. 옵셔널 바인딩(if let이나 guard let)과 함께 사용하면 더욱 안전하게 타입 변환을 처리할 수 있다.

NotificationCenter를 활용하는 예시

1. 키보드 이벤트 처리 (ex. 텍스트 필드가 키보드에 가리지 않도록 뷰를 올리거나 내리는 경우)

NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)

2. 앱 상태 변화 감지 (ex. 데이터 동기화, 타이머 일시정지, 사용자 세션 관리)

앱이 foreground에서 사용되다가 background로 전환될 때, 혹은 반대의 경우, 필요한 작업을 수행하기 위해 NotificationCenter를 사용

NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(applicationWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)

3. 네트워크 상태 변화 감지 (ex. 오프라인 모드 전환, 네트워크 연결 재시도 등)

4. 사용자 설정 변화 감지 (ex.테마 변경, 알림 설정 변경 등)

NotificationCenter.default.addObserver(self, selector: #selector(settingsDidChange), name: UserDefaults.didChangeNotification, object: nil)

5. 오디오 인터럽션 감지 (ex. 오디오 재생, 일시정지 및 재개)

오디오 재생 중 전화나 다른 오디오 앱이 실행될 때 오디오 인터럽션을 감지하기 위해 사용.

NotificationCenter.default.addObserver(self, selector: #selector(handleAudioSessionInterruption), name: AVAudioSession.interruptionNotification, object: AVAudioSession.sharedInstance())

6. 데이터 업데이트 감지 (ex. 모델 데이터 변경 시 TableView 리로드)

7. 앱 간 데이터 공유

앱 extension(widget, 키보드 등)과 같은 경우, 주 앱과 익스텐션간 데이터를 공유할 때 사용.

8. 블루투스 상태 변화 감지 (ex. 블루투스 기기 연결 시 특정 기능 활성화)

NotificationCenter.default.addObserver(self, selector: #selector(bluetoothDidConnect), name: .bluetoothDeviceDidConnect, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(bluetoothDidDisconnect), name: .bluetoothDeviceDidDisconnect, object: nil)
profile
정체되지 않는 성장

0개의 댓글