Swift에서 NSNotification에 대한 관찰자를 제거하는 곳은 어디입니까?


83

및 사용할 수 없기 NSNotification때문에 Swift 에서 관찰자를 어디에서 제거해야 합니까?viewDidUnloaddealloc()


요즘에는 블록 스타일을 사용하지 않는 한 수동으로 제거 할 필요가 없습니다 .
Fattie 19

답변:


71

와 동일한 기능을하는 아래 방법을 사용하십시오 dealloc.

deinit {
    // Release all resources
    // perform the deinitialization
}

deinitializer는 클래스 인스턴스가 할당 해제되기 직전에 호출됩니다. init 키워드를 사용하여 intializer를 작성하는 방법과 비슷하게 deinit 키워드를 사용하여 deinitizer를 작성합니다. Deinitializer는 클래스 유형에서만 사용할 수 있습니다.

Swift Deinitializer


13
iOS 9부터는 아래 답변에 따르면 블록 기반을 사용하지 않는 한 관찰자가 자동으로 제거됩니다.
Crashalot 2017

deinitViewControllerA에 대한 @Kampai 메서드는 ViewControllerB를 푸시 할 때 호출되지 않습니다.
Anirudha Mahale

@AnirudhaMahale-아니요, ViewControllerA는 여전히 탐색 컨트롤러의 스택에 있기 때문입니다. deinitViewControllerA는 탐색 컨트롤러의 스택에 없을 때만 호출됩니다. 예 : rootViewController로 전환 (rootViewController가 ViewControllerA가 아닌 경우)
Kampai

@Kampai : 뷰 컨트롤러에 관찰자를 추가하는 것처럼 작동하지 않습니다. 리 테인 사이클에 걸려서 콜 deinit을 하지 않을 가능성이 높습니다 . 것 호출에 이상적인 장소func viewDidDisappear(_ animated: Bool)
Bhanu Birani

@BhanuBirani : "높은 기회"에 대해 언급하고있는 경우를 설명해 주시겠습니까? 글쎄, 내 경험상 나는 어떤 것도 직면하지 않았다.
Kampai

136

현재 아이폰 OS 9 (및 OS X 10.11), 당신은 관찰자를 제거 할 필요가 없습니다 당신은 블록 기반의 관찰자하지만 사용하지 않을 경우, 자신을. 시스템은 관찰자를 위해 제로화 약한 참조를 사용하기 때문에 가능합니다.

그리고 블록 기반 관찰자를 사용 하는 경우 클로저의 캡처 목록에서 자신을 약하게[weak self] 캡처 하고 메서드 에서 관찰자제거하십시오deinit . self에 대한 약한 참조를 사용하지 않으면 deinit알림 센터가 무기한으로 강력한 참조를 보유하므로 메소드 (따라서 해당 관찰자 제거)가 호출되지 않습니다.

자세한 내용 은 OS X v10.11 및 iOS 9 용 Foundation Release Notes 에서 확인할 수 있습니다 .

관찰자가 영점 약한 참조로 저장 될 수있는 경우 기본 저장소는 관찰자를 영점 약한 참조로 저장합니다. 또는 객체를 약하게 저장할 수없는 경우 (즉, 런타임을 방지하는 사용자 지정 유지 / 해제 메커니즘이 있습니다.) 개체를 약하게 저장할 수 없음) 개체를 약하지 않은 제로화 참조로 저장합니다. 이것은 옵저버가 할당 해제 방법에서 등록을 취소 할 필요가 없음을 의미합니다.

-[NSNotificationCenter addObserverForName : object : queue : usingBlock] 메서드를 통한 블록 기반 관찰자는 시스템이 여전히 이러한 관찰자에 대한 강력한 참조를 보유하고 있기 때문에 더 이상 사용하지 않을 때 등록 해제해야합니다.


1
궁금합니다. 대표자들에게도 똑같이 작동합니까? iOS8에서 델리게이트는 메모리를 차지하고 유지하지 않습니다. 나는 방법 을 작성 delegate = nil했습니다 dealloc(). 지금부터 똑같이 작동합니까?
Kampai

1
일반적으로 대리자는 약한 참조로 선언되어야하며 다른 작업은 필요하지 않습니다.
Nikola Milicevic

블록 기반 관찰자에게는 작동하지 않는다고 구체적으로 언급 했으므로 이유를 자세히 설명해 주시겠습니까? 그 주위에 방법이 있습니까? 예 : [약한 자기]
Philipp Jahoda

62

세 가지 방법을 사용할 수 있습니다.

  1. popViewController, 뒤 navigationController또는 dismissViewControllerAnimated:

    deinit {
        print("Remove NotificationCenter Deinit")
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
  2. viewDidDisappear, 이미 다음 뷰 컨트롤러가 된 후 제거하십시오.

    override func viewDidDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
  3. viewWillDisappear -다음보기를 열기 전 :

    override func viewWillDisappear(animated: Bool) {
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    

Swift 3.0 구문 :

NotificationCenter.default.removeObserver(self)

1
deinit이 여기에서 가장 좋은 선택이라고 생각합니다.
Glenn Posadas

@Nikola Milicevic에 따르면 iOS 9부터는 블록 기반을 사용하지 않는 한 관찰자가 자동으로 제거됩니다.
Crashalot 2017

컨트롤러를 떠날 때 관찰자를 제거하면 관찰자를 갖는 목적이 무효화됩니까? 그리고 deinit은 스토리 보드를 사용하지 않고 프로그래밍 방식으로 한 클래스에서 다른 클래스로 이동할 때만 작동합니까?
Cyril

21

Swift 4.2에서 이것은 관찰자를 제거 할 수있는 방법 중 하나입니다.

deinit {
    NotificationCenter.default.removeObserver(self, name: Notification.Name.Identifier, object: nil)
}

viewDidLoad 클래스에서 addObserver 알림 설정

override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(didReceivedItemDetail), name: Notification.Name.Identifier, object: nil)
}

2
느린 네트워크 조건과 특정 사용자 활동 (예 : 바쁜보기 작업 중 이동)에서는 deinit가 호출되지 않을 수 있습니다. 나는 이것을 테스트에서 보았다.
GordonW 19

3
@GordonW 뷰 컨트롤러 수명주기가 끝날 때 deinit 메서드가 호출되지 않으면 해당 클래스에 메모리 문제가있는 것입니다.
Ashim Dahal


4

또한이 방법을 사용해야한다는 점을 지적하고 싶습니다.

func addObserver(_ observer: Any, selector aSelector: Selector, name aName: NSNotification.Name?, object anObject: Any?)

대신에

func addObserver(forName name: NSNotification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol

후자는 관찰자를 제거하지 않을 것입니다 (최근에이 문제에 빠졌습니다). iOS9을 사용하는 경우 전자는 관찰자를 제거합니다.


전자는 언제 관찰자를 제거합니까?
Shubham

확인 @Shubham 이 밖으로
남자 Daher

두 번째 방법에서 유지주기가 있고 방법에서 관찰자를 수동으로 제거하지 않았기 때문이라고 생각 dealloc합니다.
Nik Kov


1

스위프트 5

채팅 응용 프로그램이 있으므로 ChatLogViewController에서 다른 viewController로 이동 한 다음 돌아올 때마다 키보드 알림에 대한 추가 관찰자가 1 명 있습니다. 이를 제거하려면 viewController를 변경 하거나 chatLogViewController에서 사라질 때 모든 관찰자를 제거합니다 .

override func viewDidDisappear(_ animated: Bool) {    
    super.viewDidDisappear(animated)

    NotificationCenter.default.removeObserver(self)
}

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.