How do you change the detailViewController in a method - iphone

I have a view that is doing a lot of functions and when I get to the point that I am done I want to change to a newViewcontroller. if I where to do this from the rootview I just call.
NewPageViewController *newDetailViewController = [[NewPageViewController alloc] initWithNibName:#"NewPageViewController" bundle:nil];
detailViewController = newDetailViewController;
But I need to do it from my old detail (the right side)
I am downloading a file in a splitview iPad app from the right side and after the file is downloaded I need to in my method change the right side of the splitview to a new nib file so I can open and edit the file
Can someone point me in the right way.
Now I have :
-(void)changeView {
ListController *newDetailViewController = [[ListController alloc] initWithNibName:#"ListController"bundle:nil]
NSArray *viewControllers = [NSArray arrayWithObjects:[splitViewController.viewControllers objectAtIndex:0], newDetailViewController, nil];
splitViewController.viewControllers = viewControllers;
[viewControllers release];
}
-(void)downloadfile {
//I do all my work and get the file.
NSLog(#"I need to change views now.");
[self changeView];
}
I don't get any errors but the right side view is not changing.

As of iOS8 you can use the -showDetailViewController:sender: method on the UISplitViewController. See the Apple docs on UISplitViewController.

There is an NSArray *viewControllers property on the UISplitViewController class. The first item in this array is your master VC, the second in the detail VC. Re-assign this property to a new array containing the same master VC but a new details VC:
// don't forget to set the delegate of myNewDetailViewController appropriately!
myNewDetailViewController.delegate = ...
NSArray newVCs = [NSArray arrayWithObjects:[uiSplitVC.viewControllers objectAtIndex:0], myNewDetailViewController, nil];
uiSplitVC.viewControllers = newVCs;
API ref for UISplitViewController: http://developer.apple.com/library/ios/#documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
N.B: do not try replacing the master VC -- it usually goes horribly wrong somehow. I tried many many ways of replacing the master, it always went wrong in some very annoying way. Replacing the detail VC is fine though!

As #chris mentioned you can the use Delegate of UISplitViewController for iOS 8 and above which is the best possible way.
-(void)showDetailViewController:(UIViewController *)vc sender:(nullable id)sender NS_AVAILABLE_IOS(8_0);

Related

passing a string value from one view controller to a second variable view controller Xcode

I have an app in which I am loading variable view controllers depending on where the user is in the app. This is my code.
-(IBAction)buttonPressed:(id)sender;{
if (mission <1) {
gameViewController *detailViewController = [[gameViewController alloc] initWithNibName:#"gameViewController" bundle:nil];
[self.navigationController pushViewController:detailViewController animated:YES];
detailViewController.which2 = which;
}
else if (mission > 0) {
NSString *viewController = #"gameViewController";
NSString *missionViewController = [viewController stringByAppendingString:missionNo];
Class controllerClass = NSClassFromString (missionViewController);
id detailViewController = [[controllerClass alloc] initWithNibName:#"gameViewController" bundle:nil];
NSLog(#"missionViewController;%#",missionViewController);
[self.navigationController pushViewController:detailViewController animated:YES];
detailViewController .which2 = which;
}
}
everything work great except I want to pass a string from the first view controller to the second view controller which ever one that may be.
As you can see I have put in the code just above detailViewController.which2 = which;
I have created the property and synthesized NSString *which in my first view controller and NSString *which2 in all the subsequent view controllers. in the first instance where mission is <1 everything works ok and NSLog shows the string being passed. However with the second detailViewController (which is the variable view controller) I get the error Property 'which2' not found on object of type"_strong id' Does anyone have any suggestion on how to resolve this?
the other viewControllers are gameViewController1, gameViewController2, etc. Each is rather long and complex. But they all load into the same xib file gameViewController. There is a UIlabel that update to one higher once the user finishes that gameView so they can go on the the next on in the series or go back to the main menu. If they go back to the main menu the number is added to "gameViewController" so the correct one is loaded. So I can't specify which view controller is going to load since it depends on the user's place. Thus the missionViewController with the # of mission added to load the correct view controller. Each of the subsequent view controllers has a which2 created and synthesized. What if we pretend that all subsequent view controllers just had a UILabel that is going to display the string "which2 in it. All I want to do is pass the string "which" to the next viewController (whichever one that is) as "which2".
Dynamic binding allows you to send messages to an id as long as the selector exists in the project, but dot-syntax is not allowed.
Changing
detailViewController.which2 = which;
to
[detailViewController setWhich2:which];
should suppress the warning.
write this : `detailViewController .which2 = which;
just before you push navigation controller.`
UPDATE:
Use Protools to update the value.
#protocol MissionProtocol
#required
-(void) updateValue:(NSSTring*) value;
#end
Implement the protocols in your ViewControllers. i.e.
#interface MissionViewController:UIViewController<MissionProtocol>
....
#end
In your implementation file, implement the method updateValue.
-(void) updateValue:(NSString*) value
{
self.which2=value;
}
Then change your original code to:
NSString *viewController = #"gameViewController";
NSString *missionViewController = [viewController stringByAppendingString:missionNo];
Class controllerClass = NSClassFromString (missionViewController);
id<MissionProtocol> detailViewController = [[controllerClass alloc] initWithNibName:#"gameViewController" bundle:nil];
[detailViewController updateValue:which];

XCode: Single ViewController going to multiple ViewControllers

I have seen a bunch of topics where multiple ViewControllers go to one single ViewController, but not the opposite.
I am making a game where you select a game from Game_select.m and it needs to go out to one of 6 View Controllers. I've tried using storyboard and hardcoding it but neither have worked for me.
I have already imported Game1.h and Game2.h into Game_select.m.
When I run my code it always goes to Game1 ViewController.
This is code I am trying:
if(getGame1) {
//go to game1
Game1 *game1 = [[Game1 alloc] init];
[self.navigationController pushViewController:game1 animated:YES];
}
if(getGame2) {
//go to game2
Game2 *game2 = [[Game2 alloc] init];
[self.navigationController pushViewController:game2 animated:YES];
}
Thanks for the help in advanced.
Cheers.
Personally I wouldn't use navigation controllers for this case. Make all of your viewControllers subclasses of (the normal) UIViewController, then use this code to present one of your viewControllers:
Note that this code will only work if you are setting up your view programatically or if using xib's (not storyboard) then this will also work if you use initWithNibName: bundle: instead of using init
if(getGame1) {
//go to game1
Game1 *game1 = [[Game1 alloc] init];
[self presentViewController:game1 animated:YES completion:nil];
}
if(getGame2) {
//go to game2
Game2 *game2 = [[Game2 alloc] init];
[self presentViewController:game2 animated:YES completion:nil];
}
Create manual segues from your main viewController to the other viewControllers. First, click on the viewController that you want to be displayed. Make sure you have the viewController itself selected, not one of the views:
Then click on the segues tab (on the far right) and drag from the "Manual Segue" circle to the viewController you want to segue from.
Then click on the segues and give them different names in the tab like this:
Then, in your code, you will have a line like this:
[self performSegueWithIdentifier:#"showAlternate" sender:nil];
You would use that to show the viewController for the "showAlternate" identifier. You will have multiple segues with identifiers like "Game1" and Game2".
Double check that getGame1 and getGame2 are BOOL values and not some sort of object that will evaluate to YES if its non-nil. I have made this mistake many times:
NSNumber* booleanValue = #NO;
if (booleanValue) {
// this code will run
}
if ([booleanValue boolValue]) {
// this code will not run - as expected
}
Seriously, I've made this mistake tons of times.

How do I pass data from a tab bar controller to one of its tabs?

I have a UITabBarController set up in storyboard. I want to pass a dictionary of data from the tab bar controller for use in the appropriate child tab, which is a standard UIViewController.
This seems like a long questions to answer, but I really don't know where to start. I'm looking for the easiest way through this. Must I make the tabs function programmatically? Pointing me towards any useful developer documentation would also be much appreciated.
-Austin
p.s. i'm new and have so far depended on storyboard for viewcontroller transitions
It took a couple of days, but I discovered a simple solution. In my TabBarController's viewDidLoad method, I can access and set attributes of my the tabbed subviews using
[[self viewControllers] objectAtIndex:0]
or whatever index you wish to access.
Saving that as an instance of my tab1_viewController gives me a pointer to the object, from which I can get and set my property values. This was initially unclear because storyboard created the tab_viewController objects for me. I never had a chance to initialize them the way I wanted to!
Your best bet is to use notifications.
In your tab bar, you would do this:
NSDictionary *myDictionary; // Populate this with your data.
// Fire the notification along with your NSDictionary object.
[[NSNotificationCenter defaultCenter] postNotificationName:#"Some_Notification_Name"
object:myDictionary];
Then in your child tab ViewController, you would "listen" for that notification.
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(handleNotification:)
name:#"Some_Notification_Name"
object:nil];
- (void)handleNotification:(id)object {
// Use your NSDictionary object here.
}
If you got an UINavigationController as one of your UITabBarController view controllers, you can do the following:
NSArray *viewControllers = [self.tabBarController viewControllers];
UINavigationController *myNavController = (UINavigationController *)viewControllers[2];
MyViewController *myController = [[myNavController childViewControllers] firstObject];
// Remember to alloc/init objects first if the objects haven't been initialized already.
[myController.whateverArray = [[NSArray alloc] initWithArray:#[#"Example1", #"Example2"]];
[self.tabBarController setSelectedIndex:2];
Using Swift
If you have UINavigationController as one of the tabs in UITabBarController, you want to get the instance of the child view controller instead of creating a new instance and push it to the navigation view controller before changing the tab view index. You can do this...
This sample code assumes the Navigation Controller is at the first tab (index 0) and "childViewController" is embedded in the Navigation Controller.
let viewControllers = self.tabBarController?.viewControllers
let navController = viewControllers![0] as! UINavigationController
let profileViewController = self.storyboard?.instantiateViewControllerWithIdentifier("childViewController") as? ProfileViewController
profileViewController!.parameter1 = "Value1"
profileViewController!.parameter2 = "Value2"
navController.pushViewController(profileViewController!, animated: true)
self.tabBarController?.selectedIndex = 0
With Swift:
if let navController = self.tabBarController?.viewControllers?[1] as? UINavigationController{
if let testController = navController.childViewControllers.first as? MyViewController{
testController.data = data
self.tabBarController?.selectedIndex = 1
}
}
Got this working...
I have 3 view controller, I have to pass the array from one to another..
Here is what I did
Appending the data to one of Tab View Controller
NSArray *viewControllers = [self.tabBarController viewControllers];
ListViewController *listView = (ListViewController *)viewControllers[1];
listView.myArray = self.myArray;
[self.tabBarController setSelectedIndex:1];
And after that, load the view controller, that's it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
ListViewController *listView = (ListViewController *)[storyboard instantiateViewControllerWithIdentifier:#"IDListView"];

Passing an array from NSObject to a View Controller

Im fairly new to Objective-C. I am in the process of passing an array from an NSObject to a view controller (not my root). The NS object file, finishes with the array poolArray.
Ive also used self.poolArray = nil; in void(dealloc). When passing this to my view controller, what are the steps I have to take?
Edit: To be more specific to my cause, what if I was just to deal with two view controllers?
-(void)createData {
//poolFixtures being the text within each cell of my table view.
NSMutableArray *poolFixtures;
groupSections=[[NSMutableArray alloc] initWithObjects: #"Pool Stages", nil]
poolFixtures=[[NSMutableArray alloc] init];
[poolFixtures addObject:[[NSMutableDictionary alloc]
initWithObjectsAndKeys:#"This is a name",#"name",nil]];
fixtureData=[[NSMutableArray alloc] initWithObjects: poolFixtures, nil];
[poolFixtures release];
}
I have a similar set up for my second view controller. However, the titles needed for the second one require me to download data from a html file, parse them into the format i want etc. When used in the second view controller it takes a long time (I presume because of the html loading time). What I am trying to accomplish (what I thought i could do with an NSobject), is starting the data collection as soon as the user opens the app; so, by the time the user gets to the second view controller, it is loaded and ready.
Therefore I am wondering if I could do the downloading, and parsing in the root view controller, and send the array across to the second view controller for use when needed. I thought I would be able to use the createData part of my root implementation to do so.
For this, my suggestion is implement delegate methods. I guess u know about protocols in objective C. More info about delegate pattern.
Steps to do.
1. After ur app is launched, the view controller set the delegate and start downloading in background thread.
2. After the download is finished, the downloaded data will be set through the delegate methods.
Hope u will get my point. Any doubt, post it here.
I may be misunderstanding you, but this is what you typically do....
Object obj = [[Object alloc] init];
ViewController *vc = [[ViewController alloc] initWithNibName:#"NibName" bundle:nil];
// this is a public property of the viewcontroller
vc.array = [object methodThatReturnsArray];
[self.navigationController pushViewController:vc];
This is what the methodThatReturnsArray would look like
-(NSArray *)methodThatReturnsArray
{
NSArray* array = [[[NSArray alloc] init] autorelease];
// some code here that adds to the usefulness of the array
return array;
}

taking string from a text field and passing it to the previous viewController

im my app that im tring to build, i want to have a table view, where you select a row e.g email address. the view pushes to a simple page with a uitextField, when you hit the save button it pops the view controller back to the initial page, where the user can select the next field.
the issue that i am having is passing the information entered in the textfile back to the first view controller. this should be really simple, but anything i try just does not work
what is the best way to go around this.
thanks
You are probably thinking about the problem backwards. In an MVC system like Cocoa, the job of View Controllers is to manage views, not data. Create a model object to hold the data you're updating. When you create a view controller, pass the model object to it. It may update the model with changes the user makes. It should not worry about who called it, or who it returns to. It should just update the model object, and other interested parties should read the model object. As an example:
SettingsViewController would have a model object called Settings
When you dive into a detail view controller like EmailViewController, you pass the settings to it like emailViewController.settings = self.settings before presenting it.
When the user makes changes, just update the object like self.settings.emailAddress = ...
This separates your view logic from your model logic, which is a key features of Cocoa patterns. If you fight this pattern, you're going to often find yourself thinking "it sure is hard to get there from here."
You can either use a delegate method or, even simpler, just define an instance variable NSString *textEntry in the first view controller that can be set (property/synthesize) and then access that view controller from the stack.
For example, in the pushed view, do something like:
FirstViewController *firstViewController = [[[self navigationController] viewControllers] objectAtIndex:0];
[firstViewController setTextEntry:[textfield text]];
The easiest way I found to do this is using NSNotificationCenter.
In the ViewController with the TableView:
- (void)updateRowValue:(NSNotification *)notification{
NSDictionary *valuesDictionary = [[NSDictionary alloc] initWithDictionary: [notification userInfo] copyItems:NO];
NSString *newString = [valuesDictionary objectForKey:#"StringVal"]
}
This is the method called when row is selected
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
TextFieldViewController *tfvc = [[TextFieldViewController alloc] init];
[tfvc setPostNotificationString:#"updateRowValue"];
[self.navigationController pushViewController:tfvc animated:YES];
}
Now in the viewController with the textField, when you press the button to return to the previous viewController call this:
- (IBAction)saveButtonPressed{
NSArray *valuesArray = [[NSArray alloc] initWithObjects:textField.text,nil];
NSArray *keyArray = [[NSArray alloc] initWithObjects:#"StringVal",nil];
NSDictionary *dictionary = [[[NSDictionary alloc] initWithObjects:valuesArray forKeys:keyArray] autorelease];
[[NSNotificationCenter defaultCenter] postNotificationName:[self postNotificationString] object:self userInfo:dictionary];
[[self navigationController] popViewControllerAnimated:YES];
}