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];
}
Related
This is my code.
Here create the observer to Notification called Example into ViewController
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
}
From viewDidLoad register my observer
- (void)viewDidLoad
{
[self addObserverExample];
}
In my second ViewController. When tapped a button excute this code:
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:self.dictKeys userInfo:nil];
The problem I have is that the notification is never executed.
Any idea.
Have created demo for NSNotificationCenter as per your question and it's working fine for me. Here it is the link of that code: NSNotificationCenter Demo
- (void)viewDidLoad {
[super viewDidLoad];
[self addObserverExample];
}
- (void)addObserverExample
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(example:)
name:#"Example"
object:nil];
}
- (void)example:(NSNotification *)notification{
NSLog(#"Example!!!");
NSLog(#"%#",notification.userInfo);
}
- (IBAction)btnFireNotification:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Example" object:nil userInfo:#{#"key" : #"value"}];
}
I believe the problem you're having may be related to the fact that in your second view controller, you're passing self.dictKeys in the object parameter.
If you want to pass data via the NSNotificationCenter, you should use the userInfo parameter instead.
Darshan's example does this the correct way.
I want to test a certain method was called in response to an NSNotification being received
i've tried this:
_sut = mock([EAMainScreenViewController class]);
[_sut view];
[[NSNotificationCenter defaultCenter]postNotificationName:kNotificationPushReceived object:[UIApplication sharedApplication].delegate userInfo:nil];
[verify(_sut) pushReceived:anything()];
And my _sut viewDidLoad looks like this
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushReceived:) name:kNotificationPushReceived object:[UIApplication sharedApplication].delegate];
}
why does my test fail expecting 1 invocation, and receiving 0 invocations ?
btw, if i debug - the debugger does stop at the method
You should re-write your test to next:
- (void)setUp {
_sut = [[EAMainScreenViewController alloc] <properInit>];
}
- (void)tearDown {
//just in case
[[NSNotificationCenter defaultCenter] removeObserver:_sut];
}
- (void)testThatNotificationPushReceived {
[_sut viewDidLoad];
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationPushReceived object:<probably some mock> userInfo:nil];
//test something that happens with your mock
}
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.
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];
}
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.