I am using this code to implement NSNotification listener :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(addUserItemNotification:) name:kFinishFillUserDetails object:nil];
}
return self;
}
How i remove it:
-(void)viewDidUnload {
[super viewDidUnload];
[[NSNotificationCenter defaultCenter] removeObserver:self name:kFinishFillUserDetails object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
And this is how i call it :
[[NSNotificationCenter defaultCenter] postNotificationName:kFinishFillUserDetails object:nil userInfo:dic];
And i have this problem:
If i create the viewcontroller and add it to UINavigationController and then remove it from the UINavigationController and then create another controller from the same type and add it to UINavigationController, And then the NSNotification called twice and not only once.
Any idea why it happen?
This is how i create the UIViewController:
UsersViewController *usersVC = [[[UsersViewController alloc]initWithNibName:#"UsersViewController" bundle:nil] autorelease];
[[self navigationController] pushViewController:usersVC animated:NO];
viewDidUnload is deprecated since iOS 6 and it's no called anymore in the view controller life cycle.
Try moving the deregistration code into dealloc.
Gabriele Petronella has the right of it. viewDidUnload is deprecated. I find the best pattern to use when registering/unregistering NSNotifications is within the viewWillAppear:animated/viewWillDisappear:animated respectively.
Related
I want to pass an object in view A to view B, that's work, but when I repeat this method, I have a crash (Thread 1: EXC_BREAKPOINT).
I initialize in my view B as :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(hotSpotMore:) name:#"HotSpotTouched" object:nil];
}
return self;
}
- (void)hotSpotMore:(NSNotification *)notification {
self.articleVC = [[ArticlesVC alloc] init];
self.articleVC=[notification.userInfo objectForKey:#"Art"]; // ERROR LINE
}
In my View A as :
NSDictionary *myDictionary=[NSDictionary dictionaryWithObject:articles forKey:#"Art"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"HotSpotTouched" object:self userInfo:myDictionary];
I recover my object in instance variable, for the first two time, that's work and after there are a crash.
Output:
ArticlesVC setArticleVC:]: message sent to deallocated instance 0x44883f10
And in my instrument Zombie I have this eror :
An Objective-C message was sent to a deallocated 'ArticlesVC' object (zombie) at address: 0xc2d0710. 
My issue is method dealloc is called twice and I have a Zombie because my "RefCt" is set to "-1", I don't understand why this method is called twice time. How i can solve that ?
Your viewB is already dealloced, but viewA send object to viewB, which already doesn't exist. Add removeObserver into dealloc:
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
Your notification observer will be added everytime you call initWithNibName for your class.
Try removing the earlier observer before adding a new one.
you can do this in either in
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
or
- (void)viewdidUnload
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I have a webview I want to create a new instance of in certain situations.
I do it like this:
if(self.webViewController){
self.webViewController = nil;
[self.webViewController release];
}
self.webViewController = [[WebViewController alloc]initWithNibName:#"TheWebView" bundle:nil];
in self.webViewController I listen to a NSNotification
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
NSLog(#"INITING WebView");
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(doPageRequest:) name:#"doPageRequest" object:nil];
return self;
}
However if I send a message doPageRequest, it gets invoked multiple times. So my assumption is that there are still more webView Instances "active", means: When I created the new instance, the old one is not freed correctly.
You should call the [[NSNotificationCenter defaultCenter] removeObserver:self]; in the dealloc method
Add the following, and remove the removeObserver line from your init method.
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
The self changes as you recreate a viewcontroller, it's a pointer to a new part of the memory where your new ViewController resides.
So calling [[NSNotificationCenter defaultCenter] removeObserver:self]; inside the init will never remove a previous one you added in init.
Also, you set the self.webViewController = nil; before you call release on it, obviously that won't work (you're calling release on nil), so switch the order.
[self.webViewController release];
self.webViewController = nil;
I was reading Apple Documents and saw that:
Before an object that is observing notifications is deallocated, it
must tell the notification center to stop sending it notifications.
Otherwise, the next notification gets sent to a nonexistent object and
the program crashes.
I tried to crash app to learn better how it is actually working.
However, even if I did not put this code inside SecondViewController dealloc, it still does not crash after sending notification. I'am obviously adding observer and going back from secondViewController and pushing notification in viewController. So, Why do we need remove observer if this program does not crash?
[[NSNotificationCenter defaultCenter] removeObserver:self];
Rest code is:
//ViewController:
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. }
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
- (IBAction)go:(id)sender {
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self presentViewController:secondViewController animated:NO completion:^{}];
[secondViewController release], secondViewController = nil; }
- (IBAction)push:(id)sender {
// All instances of TestClass will be notified
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:self]; }
//SecondViewController:
#implementation SecondViewController
- (void)dealloc {
[super dealloc]; }
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTestNotification:)
name:#"TestNotification"
object:nil];
}
return self; }
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void) receiveTestNotification:(NSNotification *) notification {
// [notification name] should always be #"TestNotification"
// unless you use this method for observation of other notifications
// as well.
NSLog (#"Successfully received the test notification!"); }
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated. }
- (IBAction)back:(id)sender {
NSLog(#"");
[self dismissViewControllerAnimated:NO completion:^{}]; }
#Reno Jones is right.
Remove observer like this - [[NSNotificationCenter defaultCenter] removeObserver:self name:#"TestNotification" object:nil];
One more thing to add to his answer is you should remove the observer in the - (void)dealloc {} method - this is the method that is called when self is deallocated.
EDIT:
I've looked at the code and I have seen you are not using arc. one more question why are you not using ARC in your application? Do you have a good reason to stress yourself with reference counting , i do not see the point?
Second could you move the addObserver in the viewDidLoad method and see it that crashes your app.
Either dealloc method of SecondViewController is not being called because the object is still in the memory, or push:(id)sender method is not called after the controller is deallocated. Otherwise, It would definitely crash. Make sure that the methods are called by putting breakpoints.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to tell when controller has resumed from background?
How to refresh View after user enters applicationWillEnterForeground?
I want to complete recall for example HomeViewController.
I have and update function in HomeViewController and I want when user enters to call update function and reload table data.
Any class can register to UIApplicationWillEnterForegroundNotification, and react accordingly. It's not reserved to the app delegate, and helps for better separation of source code.
Create a viewDidLoad method like this for your HomeViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(yourUpdateMethodGoesHere:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
// Don't forget to remove the observer in your dealloc method.
// Otherwise it will stay retained by the [NSNotificationCenter defaultCenter]...
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
If your ViewController is a tableViewController your could also directly call the reload data function:
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:[self tableView]
selector:#selector(reloadData)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Or you could use a block:
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillEnterForegroundNotification
object:nil
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *note) {
[[self tableView] reloadData];
}];
You could declare a property in your app delegate class that would point to the HomeViewController object. Then you can call your update function in applicationWillEnterForeground.
I am unable to pass variables between 3 views in Objective C. I can pass data from one class to another as long as there are just 2, but if I add another view that needs to access the same delegate method, I am unable to do so.
Let me try to explain:
View1 accesses the delegate method declared in View2. However if I add another view called View3 and need to access delegate method for in View2, I cannot. I declared everything correctly and I am able to reference the delegate method, but still I cannot enter that reference in View3.
Two objects can not be both the delegate of a third. Is that your issue? If so, consider using NSNotification in order to send messages: several objects can subscribe to notifications.
if you want to passing data from 1 class to 3 classes , you had better use NSNotification.
you can use like this.
in the first receive class:
#implementation TestClass1
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification1:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification1:(NSNotification *) notification
{
NSLog(#"receive 1");
}
#end
in the 2nd receive class:
#implementation TestClass2
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification2:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification2:(NSNotification *) notification
{
NSLog(#"receive 2");
}
#end
in the 3rd receive class:
#implementation TestClass3
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
- (id) init
{
self = [super init];
if (!self) return nil;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotification3:)
name:#"TestNotification"
object:nil];
return self;
}
- (void) receiveNotification3:(NSNotification *) notification
{
NSLog(#"receive 3");
}
#end
in the post class:
- (void) yourMethod
{
[[NSNotificationCenter defaultCenter]
postNotificationName:#"TestNotification"
object:self];
}