Hi guys i have a dual viewcontroller.
My firstviewcontroller have a button and this button send NSNotification and secontviewController receive this notification and NSLOG any string.
But if i dont load secontView; my Notification is dont work ..
This codes in my firstViewController.m
-(IBAction)tapper:(id)sender {
[[NSNotificationCenter defaultCenter] postNotificationName:#"Twitter" object:nil];
}
and this codes in my secontViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector( receiveNotificaiton: ) name:#"Twitter" object:nil];
}
-(void)receiveNotificaiton: (NSNotification *) notification {
NSLog(#"TWİTTER");
}
How can i load second viewDidload in first viewDidload or something else?
It sounds like you want your first view controller to present the second one. Correct?
If so you should not be using notifications. You can simply present the second view controller from the first, take a look at "Presenting View Controllers from Other View Controllers"
It's not the right way post a notification to a view controller which doesn't exist yet because (as you said) it can't execute the istruction for becoming observer. So a solution can be present the second view controller and passing the notification information. Using the notification center is a good solution if the second view controller is the top view controleller and something else post the notification. I hope i helped you.
I fixed my problem with prepareForSegue method , thx them all.
Related
I'm using the below notifications to reload ViewControllerA when my app comes back from background mode. It works correctly, but the applicationEnteredForeground: method gets called every time when I open the app again. For example if I close the app when ViewControllerB or ViewControllerC is on the screen and open it again the method will be called despite the viewDidLoad of ViewControllerB doesn't contain applicationEnteredForeground: method. I would like to know that how could solve this issue? My goal is to use applicationEnteredForeground: only when ViewControllerA was on the screen before I closed the app.
As a possible solution I would just remove the NSNotificationCenter in the viewDidDisappear, but since the observer is in the viewDidLoad it won't work when the user navigates back, because viewDidLoad won't be called again. Is there any fix for this?
- (void)viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationEnteredForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
}
- (void)applicationEnteredForeground:(NSNotification *)notification {
// do stuff...
}
You should remove ViewController A's event listener on viewWillDisappear and add it in viewWillAppear. That way, VC A will only be listening when it is the visible view controller.
You can check if a view controller is on screen by checking the window property of it's view. It will work in most standard cases.
- (void)applicationEnteredForeground:(NSNotification *)notification
{
if (self.view.window == nil) {
// Not on screen
return;
}
// do stuff...
}
I have a UITabBarController, which has 4 tabs. Each one of those tabs is a separate UIViewController. I have objects on each one of those 4 VC's that use NSNotification's to perform actions upon the press of a certain object. The 4 VC's all respond to the notification in the same way because it is a similar object on each page. When this object is pressed it presents a view onto the current view controller. The problem is that if I move to any of the other 3 tabs now that view is also on their VC. That is because the notification is being responded to on all 4 tabs when it is pressed on any of the VC's. I am needing it to only respond to the VC that the user is currently on and not any of the others that are in the tab bar.
Is there a way to get this to work properly? Maybe a threshold where you can set how many times the notification can perform its selector after being called? That way I could set it to 1 and at any given time if that notification is called the selector can only be called 1 time.
The type of object implementation that I'm using requires me to use NSNotification's so there is no way to change how I interact.
edit:
This viewDidLoad method is on the top level VC for the 4 VC's in my tab bar. All 4 of them either use this directly or inherit from it.
- (void) viewDidLoad
{
...
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(didSelectItemFromCollectionView:) name:#"didSelectItemFromCollectionView" object:nil];
}
Action Handler:
- (void) didSelectItemFromCollectionView:(NSNotification *)notification
{
NSDictionary *cellData = [notification object];
if (cellData)
{
NewVC *pushToVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PushToVC"];
[self.navigationController pushViewController:pushToVC animated:YES];
}
}
Each of the 4 VC's is a UITableViewController and have cells with an object that can be pressed. This NSNotificationCenter action is what allows the operation to work.
You must have implemented the NSNotificationCenter's -addObserver:selector:name:object: method in the -viewDidLoad of every viewController
Example:
- (void)viewDidLoad
{
//...
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doSomething:)
name:#"TestNotification"
object:nil];
}
Instead of having this in -viewDidLoad, move it within -viewWillAppear and implement removeObserver:name:object: in -viewWillDisappear.
This way, only the viewController that is currently on will respond to the notification.
Example:
- (void)viewWillAppear:(BOOL)animated
{
//...
[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(doSomething:)
name:#"TestNotification"
object:nil];
}
- (void)viewWillDisappear:(BOOL)animated
{
//...
[NSNotificationCenter defaultCenter] removeObserver:self
name:#"TestNotification"
object:nil];
}
- (void)doSomething:(NSNotification *)userInfo
{
//...
//if you push a viewController then the following is all you need
[self.navigationController pushViewController:vcSomething
animated:YES];
//however.... if you're instead presenting a viewController modally then
//you should implement "-removeObserver:name:object: in this method as well
//[NSNotificationCenter defaultCenter] removeObserver:self
// name:#"TestNotification"
// object:nil];
//[self presentViewController:vcSomething
// animated:YES
// completion:nil];
//OR... in the completion parameter as:
//[self presentViewController:vcSomething
// animated:YES
// completion:^{
// [NSNotificationCenter defaultCenter] removeObserver:self
// name:#"TestNotification"
// object:nil];
// }];
}
EDIT:
You (#Jonathan) commented:
I really appreciate your answer and it has helped me out a lot! I
actually ran into one more scenario where this issue occur's and I'm
not sure how to figure it out. Right now I have a VC that presents
another VC modally. Each one has observers for the same
NSNotification. Everything performs perfectly well when I'm in the
modally presented VC, but once I dismiss that VC and return to the
underlying one I have the same issue where the notification is being
called multiple times. Do you have an idea for a solution in this
case?
Now... regarding this...
FIRSTLY... NOTE:
Multiple -addObserver:selector:name:object: will register the specified notification multiple times (means... same notification being registered for N times will call invoke the target selector N times)
Presenting a ViewController (call it Child) from, say, Parent viewController will NOT invoke the -viewWillDisappear: of the Parent
where as...
Dismissing the Child viewController will still invoke -viewWillAppear: of the Parent
This creates an imbalance in the logic and if not handled (as per the commented lines in the code example of the doSomething method above), it results in the Parent registering for the notification multiple times (as it's -viewWillAppear: method is called more often than not -viewWillDisappear:)
also see: similar question
it should be called only once so that it never gets called again
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(methodName:) name:#"name" object:nil];
});
My question is that I have one main UIViewController that allows three other UIViewControllers to be presented through it, but I am wondering if there is a way that once I dismiss one of those other three controllers, can the main UIViewController be notified or tell that it is now appearing due to the dismissal of said controller?
Thank you in advanced!
If your main view controller implements:
(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
and the presented view controllers send it that message, you will know since at that time it can query to see what the "presentedViewController" was.
When you dismiss one of the three ViewControllers, you could signal to the main ViewController that they have been dismissed via a NSNotification:
NSDictionary *viewControllerInfo = #{#"ViewControllerClass" : NSStringFromClass([self class])}
[[NSNotificationCenter defaultCenter] postNotificationName:#"ViewControllerDismissed" object:nil userInfo:viewControllerInfo];
And in your main viewController:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewControllerDismissed:) name:#"ViewControllerDismissed" object:nil];
And respond with this method:
- (void)viewControllerDismissed:(NSNotification *)notification {
NSDictionary *viewControllerInfo = [notification userInfo];
// Dictionary should be same as the one passed through the noticiation.
}
Additional note: If you are using a UIStoryboard, then you can use an unwind segue.
EDIT: Updated Dictionary to use NSStringFromClass()
I need to be notified about modal view controller presentation, I know that I can do using NSNotificationCenter posting and observing my custom notifications, but I'd like to know if these kind of notification already exist.
Thanks, Andrea
I've found a solution. I've just create an abstract class that overrides the methods for presenting a modal view, like that:
- (void) presentModalViewController:(UIViewController *)modalViewController animated:(BOOL)animated{
[[NSNotificationCenter defaultCenter] postNotificationName:PresentingModal object:self];
[super presentModalViewController:modalViewController animated: animated];
}
Of course all my view controllers inherit from it.
Hope this helps.
Basically, I have a view1 which at some point, calls view2 (via presentModalViewController:animated:). When a certain UIButton in view2 is pressed, view2 is calls a notification method in view1 and immediately afterward is dismissed. The notification method pops up an alert.
The notification method works fine and is called appropriately. The problem is, every time view1 is created (only one view1 should exist at a time), I presumably get another NSNotification being created because if I go from view0 (the menu) to view1, then back and forth a few times, I get a series of the same alert message, one after another, from the notification method as many times as I opened a view1.
Here is my code, please tell me what I'm doing wrong:
View1.m
-(void) viewDidLoad {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(showAlert:)
name:#"alert"
object:nil];
}
-(void) showAlert:(NSNotification*)notification {
// (I've also tried to swap the removeObserver method from dealloc
// to here, but it still fails to remove the observer.)
// < UIAlertView code to pop up a message here. >
}
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
View2.m
-(IBAction) buttonWasTapped {
[[NSNotificationCenter defaultCenter] postNotificationName:#"alert"
object:nil];
[self dismissModalViewControllerAnimated:YES];
}
-(void) dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Calling -dealloc doesn't automatically happen after the view controller is dismissed — there can still be some "life" left in the view controller's lifetime. In that timeframe, that view controller is still subscribed for that notification.
If you remove the observer in -viewWillDisappear: or -viewDidDisappear:, this will have a more immediate effect:
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:#"alert"
object:nil];
}
If you implement the removal of Observer in the viewWillDisappear: or viewDidDisappear: then you should not leave the addition of the observer in the viewDidLoad.
Instead put the addition of the observer in the viewWillAppear:. The problem you are having is because when any view is shown onto of the UIViewController view the removal of your observer will occur and since you added observer in viewDidLoad which will happen only once, it will be lost.
Keep in mind that this approach works well for objects you do not wish to observer while your main view is not in the fore front.
Also Keep in mind that viewDidUnload has been depreciated too.
There is nothing wrong putting removeObserver: in dealloc. Just the fact it's not called means view1 not properly releases after dismissing. Looks like something holds pointer to your view1, check for retain cycles.
Also, you shouldn't call dealloc on super.