Skip to content

[기술 공유] NotificationCenter의 removeObserver를 해야할까?

00me edited this page Nov 28, 2024 · 1 revision

문제 상황

image

NotificationCenter에서 addObserver를 한 ViewController를 removeObserver를 해주어야하는지에 대한 논의가 있었다.


문제 해결

잠깐 생각해봤을 때 이것은 맞는 말이다!

왜냐하면 코드상으로 addObserver를 할 때 self를 명시적으로 사용하기 때문이다.

이러한 코드는 보통 메모리 낭비를 초래한다.

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

그래서 이와 관련된 문서를 찾아보는데 역시, 가장 좋은 문서는 역시 공식문서

일단 첫줄은 이렇다.

Unregister an observer to stop receiving notifications.

구독을 취소하려면 remove를 해주어야한다.

다만, iOS 9 이상에서는 다르다.

If your app targets iOS 9.0 and later or macOS 10.11 and later, you do not need to unregister an observer that you created with this function. If you forget or are unable to remove an observer, the system cleans up the next time it would have posted to it.

위의 함수를 사용할 경우 별도의 unregister가 필요없다.

다만, 주의해야하는 것이 “with this function”이다.

다른 함수를 사용한다면 여전히 명시적으로 Observer을 삭제해주어야 한다.

위의 방식 말고도 addObserver(forName:object:queue:using:) 라는 함수가 있다.

  • addObserver(forName:object:queue:using:) 예시 [출처]

    let center = NotificationCenter.default
    let mainQueue = OperationQueue.main
    localeChangeObserver = center.addObserver(
        forName: NSLocale.currentLocaleDidChangeNotification,
        object: nil,
        queue: mainQueue) { (note) in
            print("The user's locale changed to: \(NSLocale.current.identifier)")
        }
    }
    let center = NotificationCenter.default
    let mainQueue = OperationQueue.main
    token = center.addObserver(
        forName: NSNotification.Name("OneTimeNotification"),
        object: nil,
        queue: mainQueue) {[weak self] (note) in
            print("Received the notification!")
            guard let token = self?.token else { return }
            center.removeObserver(token)
    }

    일회성 observe의 경우 center.removeObserver(token)을 호출해주는 것을 볼 수 있다.

    또한, retainCycle을 방지하기 위해 weak self를 사용할 것을 권장한다.

이 경우 애플은 deinit이 되기 전에 remove를 할 것을 권장한다.

You must invoke removeObserver(_:) or removeObserver(_:name:object:) before the system deallocates any object that addObserver(forName:object:queue:using:) specifies.

만약 이것을 사용하여 구현한다면 viewWillDisappear등에서 호출하는 것이 좋을 것같다.

⇒ 일단 deinit에서 removeObserver를 호출하는 코드를 없애도록 했다.


배운 점

자주 사용하던 addObserver(_:selector:name:object:) 외에 다르게 옵저버를 추가하는 방법이 있다는 것을 알았다.

기본적으로 addObserver(_:selector:name:object:)의 경우 iOS9.0이상에서는 삭제된다는 사실을 알았다.

다만, 다른 방법의 경우 deinit이 되기 전 에 옵저버를 삭제해야한다는 것을 알았다.


참조 링크

addObserver(forName:object:queue:using:) | Apple Developer Documentation

addObserver(_:selector:name:object:) | Apple Developer Documentation

removeObserver(_:name:object:) | Apple Developer Documentation

Clone this wiki locally