How to push a View in a NavigationController which is containing in another tab in a TabBarController? - iphone

I have a TabBarController with 2 tabs, in one is a MapView and in the other one a simple TableView in a NavigationController. Both display Data from the same source. If any Data in the table is tapped, I add a DetailViewController to the NavigationController and show more details. Now on the MapView I also want to open this DetailViewController when the Data is tapped in the map. What's the best way to do this? I tried some with Notification but this doesn't work well because the TableViewController is finished loading (and registered as an observer) after the Notification is sent.
Here's my code:
MapViewController:
- (IBAction)goToNearestEvent:(id)sender {
if (currentNearestEvent) {
[[self tabBarController] setSelectedIndex:1];
NSDictionary *noteInfo = [[NSDictionary alloc] initWithObjectsAndKeys:currentNearestEvent, #"event", nil];
NSNotification *note = [NSNotification notificationWithName:#"loadDetailViewForEvent" object:self userInfo:noteInfo];
[[NSNotificationCenter defaultCenter] postNotification:note];
[noteInfo release];
}
}
TableViewController:
- (void)viewDidLoad {
[super viewDidLoad];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(loadDetailViewForEvent:)
name:#"loadDetailViewForEvent"
object:nil];
}
- (void)loadDetailViewForEvent:(NSNotification *)note {
Event *e = [[note userInfo] objectForKey:#"event"];
[self loadEventDetailViewWithEvent:e];
}
So I'm very new to iOS / Cocoa programming. Maybe my approach is the wrong choice. So I hope anybody could tell me how to solve such things the right way.
I forgot to declare my structure clearly:
- UITabBarController
- MapView (1)
- NavigationControllerContainer
- NavigationControllerView (2)
- TableView
I want to push a new View from the MapView (1) to the NavigationControllerView (2).

If you're going to use notifications, the fix is to force the second tab to be "created" before it's displayed.
Something like:
UIViewController *otherController = [[[self tabBarController] viewControllers] objectAtIndex:1];
otherController.view; // this is magic;
// it causes Apple to load the view,
// run viewDidLoad etc,
// for the other controller
[[self tabBarController] setSelectedIndex:1];

I don't have access to my code, but I did something similar to:
[[self.tabBarController.viewControllers objectAtIndex:1] pushViewController:detailView animated:YES];
Give this a try and let me know.

I think the observer/notification pattern is the right one. However, you normally want "controllers" to observe "model" objects.
I would create a Model object that contains the selected Event.
When each viewController is loaded, it looks at the "Model" object and directs itself to the selected event.
When any of the viewControllers changes the selected event, it does so in the Model, and then the notification propagates to the other(s) controllers.

Related

Present another View Controller from SkScene

I'm trying to present another viewController from my "SkScene".
This is my main viewController(tuViewController)
Code:
-(void) openTweetSheet{
FacebookLikeViewDemoViewController *ctrl = [[FacebookLikeViewDemoViewController alloc] initWithNibName:#"FacebookLikeViewDemoViewController" bundle:nil];
[self presentViewController:ctrl animated:YES completion:nil];
}
This is my "SkScene":
tuViewController *viewController = [[tuViewController alloc]init];
[viewController openTweetSheet];
And the viewController which i want to present is FacebookLikeViewDemoViewController and i need to have way back to "SkScene".
And i got sigabrt error, i tried few ways to present viewController but always with failure, one time i got swap to viewController but it was entirely black. I read a lot how to perform that, but i personally can't figure out. I appreciate your help.
I tried too with Notification Center.
Main viewController
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(goToGameOverViewController:)
name:#"GoToGameOverViewController"
object:nil];
-(void)goToGameOverViewController:(NSNotification *) notification {
FacebookLikeViewDemoViewController *helpVC = [[FacebookLikeViewDemoViewController alloc]initWithNibName:#"HelpViewController" bundle:nil];
UIViewController *rootVC = [UIApplication sharedApplication].keyWindow.rootViewController;
[rootVC presentViewController:helpVC animated:YES completion:nil];
}
SkScene
[[NSNotificationCenter defaultCenter]
postNotificationName:#"GoToGameOverViewController" object:self];
But i got the same error. I prefer to figure out why the way with notification won't work.
I assume by your question that you are looking to do some social media posting.
You can either pass a reference for your View Controller to your SKScene or you can use NSNotificationCenter instead. I prefer to use the latter.
First make sure you have added the Social.framework to your project.
Import the social framework into your View Controller #import <Social/Social.h>
Then in your View Controller's viewDidLoad method add this code:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(createTweet:)
name:#"CreateTweet"
object:nil];
Next add this method to your View Controller:
-(void)createTweet:(NSNotification *)notification
{
NSDictionary *tweetData = [notification userInfo];
NSString *tweetText = (NSString *)[tweetData objectForKey:#"tweetText"];
NSLog(#"%#",tweetText);
// build your tweet, facebook, etc...
SLComposeViewController *mySLComposerSheet = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeTwitter];
[self presentViewController:mySLComposerSheet animated:YES completion:nil];
}
At the appropriate location in your SKScene, (won game, lost game, etc...) add this code:
NSString *tweetText = #"I just beat the last level.";
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:tweetText forKey:#"tweetText"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreateTweet" object:self userInfo:userInfo];
The above code sends a NSNotification, with text, which your View Controller will pick up and execute the specified method (which is createTweet in the above example).

Call [tableView reloadData]; on a viewController from a modalViewController

I have a modalViewController that comes up over the top of a viewController with a tableView. When the user clicks a button on the modalViewController I want to reload the tableView within the viewController with this:
[tableView1 reloadData];
I do not want to put the reload in the viewDidAppear or viewWillAppear methods as they get called when i do not need the tableView to reload (i.e. when the user clicks the back button to return to the tableView).
Is there a way to do this?
Try
1) write one method which reloads the table data.
2) Call it on the back button clicked.
This is the classic delegate pattern problem, in your modal view controller you need a delegate reference to the current view controller presenting it
//Modal
#protocol ModalVCDelegate
- (void)tappedBackButton;
#end
#class ModalVC: UIViewController
#property id<ModalVCDelegate> delegate;
#end
#implementation
- (void)backButtonTapped:(id)sender
{
if (self.delegate)
[self.delegate tappedBackButton];
}
#end
Now, in your presenting VC, just process this delegate message
//Parent VC
- (void)showModal
{
ModalVC *vc = [ModalVC new];
vc.delegate = self;
//push
}
- (void)tappedBackButton
{
[self.tableView reloadData];
//close modal
}
You can use delegate . If find it more harder then alternative is to use NSNotificationCenter. You can see accepted answer for Refreshing TableView. This is really very short, easy and understandable way.
using Notification like bellow Method:-
Create NSNotificationCenter at yourViewController's ViewdidLoad Mehod
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(ReloadDataFunction:)
name:#"refresh"
object:nil];
[super viewDidLoad];
}
-(void)ReloadDataFunction:(NSNotification *)notification {
[yourTableView reloadData];
}
Now you can Call this Notification from your modelViewController BackButton or else you want from calling this Refresh notification like putting this line of code:-
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:self];
NOTE: postNotificationName:#"refresh" this is a key of particular Notification
Try to use this one
Make a Button and click on this button and than you can reload your data.
This button make custom and use it on background.
- (IBAction)reloadData:(id)sender
{
[tblView reloadData];
}
You can use NSNotification to refresh table on ViewController.
Inside viewController :
-(void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
Write code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reloadMainTable:)
name:#"ReloadTable"
object:nil];
- (void) reloadMainTable:(NSNotification *) notification
{
[tableView reload];
}
Inside ModelViewController:
[[NSNotificationCenter defaultCenter]
postNotificationName:#"ReloadTable"
object:nil];
Here you can also send custom object instead of nil parameter. But be care full about removal of NSNotification observer.

Open View from didReceiveRemoteNotification

I have this question asked few times and I have tried a few different methods but have not been successful.
The latest method I have tried is as followed :
I included the ViewController that I wanted to show. I then put this code in the didReceiveRemoteNotification method.
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
// [self.window.rootViewController presentViewController:pvc animated:YES completion:nil];
[(UINavigationController *)self.window.rootViewController pushViewController:pvc animated:NO];
This did not work. I think the problem I may be having is that my initial view is not a navigation controller like a lot of the examples show.
This is a picture of my story board> The VC that I want to send the user to is the car finder (bottom right)
Can someone explain to me what I might be doing wrong?
You could use basically postNotification when you receive the Remote Notification
for exmaple in your didReceiveRemoteNotification post notification like this
[[NSNotificationCenter defaultCenter] postNotificationName:#"pushNotification" object:nil userInfo:userInfo];
now in your FirstViewController's you can register the FirstViewController for this notification like this
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(pushNotificationReceived) name:#"pushNotification" object:nil];
and in your method
-(void)pushNotificationReceived{
CarFinderViewController *pvc = [[CarFinderViewController alloc] init];
[self presentViewController:pvc animated:YES completion:nil];
}
don't forget to remove the observer from notification in your dealloc method
-(void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
I think the simplest solution would be to show the CarFinderViewController as a modal view instead of trying to push it to a navigation controller which may or may not be visible at the time.
Another important point to avoid further inconsistencies I'd recommend you instantiate your CarFinderViewController from the storyboard instead of directly through the class methods.
Something like:
UIViewController * vc = self.window.rootViewController;
// You need to set the identifier from the Interface
// Builder for the following line to work
CarFinderViewController *pvc = [vc.storyboard instantiateViewControllerWithIdentifier:#"CarFinderViewController"];
[vc presentViewController:pvc animated:YES completion:nil];

how to get textfield value of second modal view to the textfield of first modal view [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Passing Data between View Controllers
I have 2 modal views. The first modal view is used to edit quantity and price; the second modal view is used when we click the price textfield of first modal view in order to give give reason why we change the price and we can put new price in price textfield of modal view. I want the price in first modal view change when I set the price in second modal view. How to catch the value of second modal view to put in first modal view ?
Use NSNotification center
You have to addobserver event in First Modalview
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(reload:) name:#"refresh" object:nil];
}
- (void)reload:(NSNotification *)notification {
textfield.text= [[notification userInfo] valueForKey:#"price"] ;
}
In second modalview you have to post notification after you complete edit
(pass your textfield value)
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:#"333" forKey:#"price"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"refresh" object:nil userInfo:userInfo]
;
Finally remove observer
-
(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:#"refresh" object:nil];
}
You can used Singleton just to save some data on that class
The following simple steps will make you able to do this.
In the first Modal ViewController, you can declare a function like
- (void) setUpdatedValueWithValue: (NSString *) newValue
{
self.objTextField.text = newValue;
}
Declare this function on the header file too, so that we can access it from the other class.
In the second Modal ViewController
SecondViewController.h
#interface SecondViewController : UIViewController
{
id objFirstViewController;
}
#property (nonatomic, retain) id objFirstViewController;
#end
SecondViewController.m
#implementation SecondViewController
#synthesize objFirstViewController;
#end
Before you present the SecondViewController pass the object of FirstViewController to SecondViewController like,
- (void) presentSecondViewController
{
SecondViewController *objSecondViewController = [[SecondViewController alloc] init];
objSecondViewController.objFirstViewController = self;
[self presentModalViewController: objSecondViewController animated: YES];
[objSecondViewController release];
objSecondViewController = nil;
}
Then, in the function you are calling to dismiss the SecondViewController after the value edit you can do like,
- (void) finishEdit
{
if([objFirstViewController respondsToSelector: #selector(setUpdatedValueWithValue:)])
{
[objFirstViewController performSelector: #selector(setUpdatedValueWithValue:) withObject: editedTextView.text];
}
[self dismissModalViewControllerAnimated: YES];
}
Hope this helps.
set you object with your keyword
[[NSUserDefaults standardUserDefaults]setObject:#"value of second modal view" forKey:#"keyName"];
than get that object in first modal view
NSString *name = [[NSUserDefaults standardUserDefaults]objectForKey:#"keyName"];

How to determine what the prior visibleViewController in UINavigationControllers?

I'm switching views in the context of a navigation view heirarchy, and I want to be able to determine at switch time what the prior view was that is being pushed under the new view.
I'm trying this in a UINavigationControllerDelegate:
(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
NSLog( #"Switching from %# to %#",
NSStringFromClass( [[navigationController visibleViewController] class] ),
NSStringFromClass( [viewController class] )
);
}
I get this:
2009-08-05 20:05:21.274 App Name [85913:20b] Switching from
ManagementScreen to ManagementScreen
unfortunately it appears that before "will" is called, it is already swapped out in the state of the UINavigationController such that viewController passed in is always the same as the visibleViewController on the UINavigationController (and also the topViewController property, not demonstrated here but I tried it with the same code).
I would like to avoid extending the navigation view controller, and honestly while I can easily put a property on the delegate - however I'm wondering if this behavior is possible within the existing framework (seems will should be called before it happens where as did happens after, but it seems the state of the navigation controller is modified before either).
Thanks!
I don't think the answers that use the UINavigationControllerDelegate work because, as the question points out, by the time the delegate is called the view controller that will be displayed is already the value for navigationController.topViewController and navigationController.visibleViewController.
Instead, use observers.
Step 1. Set up an observer to watch for the UINavigationControllerWillShowViewController notification:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(viewControllerChange:) name:#"UINavigationControllerWillShowViewControllerNotification" object:self.navigationController];
Step 2. Create the notification callback (in this example called viewControllerChange) and use keys in the notifications userInfo dictionary to see the last and next view controllers:
(void)viewControllerChange:(NSNotification *)notification {
NSDictionary *userInfo = [notification userInfo];
NSLog(#"Switching from %# to %#", [[userInfo objectForKey:#"UINavigationControllerLastVisibleViewController"] class], [[userInfo objectForKey:#"UINavigationControllerNextVisibleViewController"] class]);
}
- (void)navigationController:(UINavigationController*)nc
didShowViewController:(UIViewController*)vc
animated:(BOOL)animated
{
NSLog(#"Switching from %# to %#",
NSStringFromClass([vc class]),
NSStringFromClass([[nc.viewControllers objectAtIndex:[nc.viewControllers count]-1] class]));
}