목표 C : NSNotification에 대한 관찰자를 제거 할 위치는 어디입니까?
객관적인 C 클래스가 있습니다. 그 안에 init 메소드를 만들고 NSNotification을 설정했습니다.
//Set up NSNotification
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(getData)
name:@"Answer Submitted"
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self]
이 수업 에서는 어디에 설정 합니까? 나는 a UIViewController
에 대해 그것을 viewDidUnload
메소드에 추가 할 수 있다는 것을 알고 있습니다. 그래서 방금 목표 c 클래스를 생성했다면 무엇을해야할까요?
일반적인 대답은 "더 이상 알림이 필요하지 않은 즉시"입니다. 이것은 분명히 만족스러운 대답이 아닙니다.
관찰자 등록을 완전히 취소 할 수있는 마지막 기회이므로 관찰자로 사용하려는 클래스의 [notificationCenter removeObserver: self]
메서드 dealloc
에 호출을 추가하는 것이 좋습니다 . 그러나 이것은 알림 센터가 죽은 개체를 알리기 때문에 충돌로부터 만 보호합니다. 개체가 아직 알림을 적절하게 처리 할 수있는 상태가 아니거나 더 이상없는 경우 알림 수신으로부터 코드를 보호 할 수 없습니다. 이를 위해 ... 위를 참조하십시오.
편집 (답은 내가 생각했던 것보다 더 많은 주석을 끌어들이는 것 같기 때문에) 내가 여기서 말하려는 것은 : 알림 센터에서 관찰자를 제거하는 것이 가장 좋은시기에 대한 일반적인 조언을 제공하는 것은 정말 어렵습니다.
- 사용 사례 (어떤 알림이 관찰됩니까? 언제 전송됩니까?)
- 관찰자의 구현 (알림을받을 준비가 된 시점은 언제입니까? 더 이상 준비되지 않은 시점은 언제입니까?)
- 관찰자의 의도 된 수명 (보기 또는보기 컨트롤러와 같은 다른 개체에 연결되어 있습니까?)
- ...
그래서 제가 생각해 낼 수있는 가장 일반적인 조언은 앱을 보호하는 것입니다. 적어도 한 번의 실패 가능성에 대비하여에서 removeObserver:
춤을 추십시오. dealloc
그것이 (객체의 삶에서) 마지막 지점이기 때문에 깨끗하게 할 수 있습니다. 이것이 의미하지 않는 것은 " dealloc
이 호출 될 때까지 제거를 연기하면 모든 것이 잘 될 것입니다"입니다. 대신 개체가 더 이상 알림을받을 준비가되지 않거나 필요하지 않으면 즉시 관찰자 를 제거합니다 . 바로 그 순간입니다. 안타깝게도 위에서 언급 한 질문에 대한 답을 알지 못해서 그 순간이 언제인지 짐작조차 할 수 없습니다.
항상 안전하게 removeObserver:
객체를 여러 번 사용할 수 있습니다 (주어진 관찰자와의 첫 번째 호출을 제외하고 모두 nops가됩니다). 그러니 : dealloc
확실하게하기 위해 (다시) 생각해보세요 .하지만 무엇보다도 먼저 : 적절한 순간에하세요 (사용 사례에 따라 결정됨).
참고 : 이것은 100 % 테스트 및 작동되었습니다.
빠른
override func viewWillDisappear(animated: Bool){
super.viewWillDisappear(animated)
if self.navigationController!.viewControllers.contains(self) == false //any other hierarchy compare if it contains self or not
{
// the view has been removed from the navigation stack or hierarchy, back is probably the cause
// this will be slow with a large stack however.
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
PresentedViewController
override func viewWillDisappear(animated: Bool){
super.viewWillDisappear(animated)
if self.isBeingDismissed() //presented view controller
{
// remove observer here
NSNotificationCenter.defaultCenter().removeObserver(self)
}
}
목표 -C
에서 iOS 6.0 > version
의 더 나은 것은에서 관찰자를 제거하기 위해 viewWillDisappear
같은 viewDidUnload
방법이 사용되지 않습니다.
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
많은 배 더있다 remove observer
뷰가 제거 된 경우 navigation stack or hierarchy
.
- (void)viewWillDisappear:(BOOL)animated{
if (![[self.navigationController viewControllers] containsObject: self]) //any other hierarchy compare if it contains self or not
{
// the view has been removed from the navigation stack or hierarchy, back is probably the cause
// this will be slow with a large stack however.
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
}
}
PresentedViewController
- (void)viewWillDisappear:(BOOL)animated{
if ([self isBeingDismissed] == YES) ///presented view controller
{
// remove observer here
[[NSNotificationCenter defaultCenter] removeObserver:observerObjectHere];
}
}
iOS 9부터 더 이상 관찰자를 제거 할 필요가 없습니다.
OS X 10.11 및 iOS 9.0에서 NSNotificationCenter 및 NSDistributedNotificationCenter는 더 이상 할당이 취소 될 수있는 등록 된 관찰자에게 알림을 보내지 않습니다.
If the observer is added to a view controller, I strongly recommend adding it in viewWillAppear
and removing it in viewWillDisappear
.
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
In general I put it into the dealloc
method.
In swift use deinit because dealloc is unavailable:
deinit {
...
}
Swift documentation:
A deinitializer is called immediately before a class instance is deallocated. You write deinitializers with the deinit keyword, similar to how intializers are written with the init keyword. Deinitializers are only available on class types.
Typically you don’t need to perform manual clean-up when your instances are deallocated. However, when you are working with your own resources, you might need to perform some additional clean-up yourself. For example, if you create a custom class to open a file and write some data to it, you might need to close the file before the class instance is deallocated.
*edit: This advice applies to iOS <= 5 (even there you should be adding in viewWillAppear
and removing in viewWillDisappear
- however the advice applies if for some reason you've added the observer in viewDidLoad
)
If you've added the observer in viewDidLoad
you should remove it in both dealloc
and viewDidUnload
. Otherwise you'll end up adding it twice when viewDidLoad
is called after viewDidUnload
(this will happen after a memory warning). This isn't necessary in iOS 6 where viewDidUnload
is deprecated and won't be called (because views are no longer automatically unloaded).
In my opinion, the following code makes no sense in ARC:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
In iOS 6, there's also no sense in removing observers in viewDidUnload
, because it has been deprecated now.
To sum up, I always do it in viewDidDisappear
. However, it depends on your requirements also, just like @Dirk said.
I think I found a reliable answer! I had to, as the answers above are ambiguous and seem contradicting. I looked through Cookbooks and Programming Guides.
First, the style of addObserver:
in viewWillAppear:
and removeObserver:
in viewWillDisappear:
does not work for me (I tested it) because I am posting a notification in a child view controller to execute code in the parent view controller. I would only use this style if I was posting and listening for the notification within the same view controller.
The answer I will rely on the most, I found in the iOS Programming: Big Nerd Ranch Guide 4th. I trust the BNR guys because they have iOS training centers and they are not just writing another cookbook. It is probably in their best interest to be accurate.
BNR example one: addObserver:
in init:
, removeObserver:
in dealloc:
BNR example two: addObserver:
in awakeFromNib:
, removeObserver:
in dealloc:
…when removing observer in dealloc:
they don’t use [super dealloc];
I hope this helps the next person…
I am updating this post because Apple now has almost completely gone with Storyboards so the above mentioned may not apply to all situations. The important thing (and the reason I added this post in the first place) is to pay attention if your viewWillDisappear:
is getting called. It wasn't for me when the application entered background.
The accepted answer is not safe and could cause a memory leak. Please do leave the unregister in dealloc but also deregister in viewWillDisappear (that is of course if you register in viewWillAppear)....THAT'S WHAT I DID ANYWAYS AND IT WORKS GREAT! :)
It is important to notice also that viewWillDisappear
is called also when the view controller present a new UIView. This delegate simply indicate that the view controller main view is not visible on the display.
In this case, deallocating the notification in viewWillDisappear
may be inconvenient if we are using the notification to allow the UIview to communicate with the parent view controller.
As a solution I usually remove the observer in one of these two methods:
- (void)viewWillDisappear:(BOOL)animated {
NSLog(@"viewController will disappear");
if ([self isBeingDismissed]) {
NSLog(@"viewController is being dismissed");
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}
}
-(void)dealloc {
NSLog(@"viewController is being deallocated");
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"actionCompleted" object:nil];
}
For similar reasons, when I issue the notification the first time, I need to account for the fact that any time a view with appear above the controller then viewWillAppear
method is fired. This will in turn generate multiple copy of the same notification. Since there isn't a way to check if a notification is already active, I obviate the problem by removing the notification before adding it:
- (void)viewWillAppear:(BOOL)animated {
NSLog(@"viewController will appear");
// Add observers
[[NSNotificationCenter defaultCenter] removeObserver:self name:@"imageGenerated" object:nil]; // This is added to avoid duplicate notifications when the view is presented again
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receivedImageFromCameraOrPhotolibraryMethodOnListener:) name:@"actionCompleted" object:nil];
}
SWIFT 3
There are two cases of using notifications: - they are needed only when the view controller is on screen; - they are needed always, even if user opened another screen over current.
For the first case the correct place to add and remove observer are:
/// Add observers
///
/// - Parameter animated: the animation flag
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
NotificationCenter.default.addObserver(...)
}
/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
for the second case the correct way is:
/// Add observers
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(...)
}
/// Remove observers
///
/// - Parameter animated: the animation flag
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if self.isBeingDismissed // remove only when view controller is removed disappear forever
|| !(self.navigationController?.viewControllers.contains(self) ?? true) {
NotificationCenter.default.removeObserver(self)
}
}
And never put removeObserver
in deinit{ ... }
- it's a MISTAKE!
override func viewDidLoad() { //add observer
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector:#selector(Yourclassname.method), name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}
override func viewWillDisappear(_ animated: Bool) { //remove observer
super.viewWillDisappear(true)
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "NotificationIdentifier"), object: nil)
}
참고URL : https://stackoverflow.com/questions/6469209/objective-c-where-to-remove-observer-for-nsnotification
'developer tip' 카테고리의 다른 글
clipsToBounds는 어떻게 작동합니까? (0) | 2020.08.21 |
---|---|
"else if"는 단일 키워드입니까? (0) | 2020.08.21 |
Swift로 둘 이상의 사용자 지정 셀이있는 UITableview (0) | 2020.08.21 |
동일한 파일에 대해 입력 유형 = 파일 "변경"을 감지하는 방법은 무엇입니까? (0) | 2020.08.20 |
정규식의 모든 문자에 대한 기호? (0) | 2020.08.20 |