I am trying to create a UITableView using storyboard but I came to something that at the end may be easy but I have no idea how to solve it.
First of all let me point out that I know that one of the limitations of storyboards is that you will have to dig through the storyboard to find information about a view you have and link it to the app delegate.
I have create my mutable array and the information that I will use in the table in the app delegate and now I want to reference that UITableView to the app delegate. The hierarchy goes like that
First I have the root view that once you click on a button it will redirect you to the second view
Inside the second view there is another button that once you press it it will redirect you to the UINavigationController
The UINavigationController contains the UITableView.
Therefore as you can see there are two views before the navigation control and the UITableView.
Here is the code I am trying to use but it does not work
UIViewController *viewController = (UIViewController *)self.window.rootviewController;
// The next line refers to the second view but does not work at all
UIViewController *secondView = [[UIViewController viewController] objectAtIndex:1];
//Then the following line is to redirect from the second view to the navigation controller
UINavigationController *navigationController =[[secondView viewController] objectAtIndex:0];
//Then is the table view
BuildingsViewController *buildingsViewController = [[navigationController viewControllers] objectAtIndex:0];
The above code does not work. Can anyone please help me?
Thanks a lot
If this code is in the app delegate there are a variety of reasons why it will probably not work. Firstly you appear to be mixing up View's, ViewControllers and Navigation controllers with what you are trying to do. Secondly there is no guarantee at the time you are trying to do this that all of the views/viewcontrollers have yet been created yet or are joined in the way they will be when the final building view controller is rendered.
What you could try instead is in your BuildingsViewController (which you say is your table view controller) you can get a handle to the App Delegate by using
MyAppDelegate *myAppDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
Once you have a handle to the delegate you can simply reference your mutable array structure etc. that you created on it from within your BuildingsViewController.
e.g. in the 'numberOfRowsInSection' method:
MyAppDelegate *myAppDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
NSMutableArray *myBuildings = myAppDelegate.buildingArray;
return [myBuildings count];
Or in the cellForRowAtIndexPath method:
// something like this but using your names for app delegate, building array and the accessor for the building name
MyAppDelegate *myAppDelegate = (MyAppDelegate *)[UIApplication sharedApplication].delegate
NSMutableArray *myBuildings = myAppDelegate.buildingArray;
cell.textLabel.text = [myBuildings objectAtIndex indexPath.row].theBuildingName;
Related
Wondering how I can set properties of view controllers that are already on the NavigationController's stack
My situation:
I want to set up an image uploading flow like this
(Navigation Stack)
RootViewController -> TakePictureViewController -> EditPictureViewController -> UploadPictureViewController
When user confirms the upload from the UploadPictureViewController, rather than start to upload, I want to set an NSDictionary property on RootViewController which contains the upload query, then pop the navigation stack back down to the RootViewController and have it handle initiating and status reporting of the query.
Here's my code in the uploadpictureviewcontroller, currently, the code does pop to the right view controller, but the uploadPackage property is still nil, also I have tried to -setUploadPackage
RootViewController *rvc = (RootViewController *)[self.navigationController.viewControllers objectAtIndex:0];
rvc.uploadPackage = uploadPackage;
[self.navigationController popToViewController:rvc animated:YES];
All help appreciated, thanks.
try using [self.navigationController popToRootViewControllerAnimated:YES]. That should do it.
EDIT:
If you have only one instance of RootViewController, then you can set it up as a singleton and therefore you can access it from any other controller (just like the appDelegate). To do so you need to add the following to your RootViewController.m under synthesize...; :
static RootViewController *rootViewController;
+(id)sharedRootController {
return rootViewController;
}
inside your init method for RootViewController add the following line:
rootViewController = self;
now back to your UploadPictureViewController you can set the uploadPackage like this:
RootViewController *rvc = [RootViewController sharedRootController];
rvc.uploadPackage = uploadPackage;
Please note that you should NOT use the singleton method if there is to be more than one instance of RootViewController.
hope this helps!
I have an iPhone Application with multiple view controllers , in all view controller's header is common.
I dont want to use the same method and create common view in all controllers.
So My questions is how do i use this common view in all controllers.
Use initWithNibNamed:"name of your xib" when you alloc your new view controller. It's simple.
Same but we can avoid defining a variable -
[self.view addSubview:[[(NavAppAppDelegate *)[[UIApplication sharedApplication] delegate] headerview] view]];
ok so you have to create it in Application Delegate once.
in .h
#property(nonatomic,strong) uiviewcontroller headerview;
in .m
#synthesize headerview=_headerview;
then alloc it in "didFinishLaunchingWithOptions" in appdelegate as singleton
self.headerview = [[headerview alloc] initWithNibName:#"headerview" bundle:nil];
So every time you want to add it to your view.
Create object from application delegate in your class after import it.
applicationdelegate app = [uiapplication sharedapplication]delegate];
[self.view addsubview:app.headerview.view];
I have a TabBarController which is set up with multiple ViewControllers at launch. When the user clicks a button I want to send them to a different ViewController in the TabBarController, and pass data through a delegate.
I have a protocol and delegate set up. However, when do you set the delegate since all the ViewControllers are in the TabBarController
Is this possible, how can I pass data to another ViewController in the TabBar when the user clicks a button. Any ideas, I'd really like to use a delegate.
- (IBAction)sendData:(id)sender
{
[self.delegate setStringData:strData];
self.tabBarController.selectedIndex = 0;
}
Edit:
So let's say I have a TabBarController with two ViewControllers called ViewControllerOne and ViewControllerTwo.
I have ViewControllerTwo set up as the delegate and protocol. This is the ViewController that will send data to ViewControllerOne after the button is pressed. ViewControllerOne implements protocol and contains the method setStringData which should be called after the button in ViewControllerTwo is pressed.
From a UIViewController you want to change the selected tab bar index and pass data.
I suggest you add a function in you app delegate for this.
That way your UIViewController won't be tied with a UITabBar (if tomorrow you want to use a different UI idiom, you will just have to change the implementation of your function in your app delegate).
To pass data, i you could try to introspection in your function : you take the current UIViewController of the new selected tab index, verify it responds to your selector and call the function.
Edit :
Let's assume your 'just' have to change the selected tabBar index (e.g. your UIViewController will always be the same on the new tab bar index).
In your first View Controller :
- (IBAction)sendData:(id)sender
{
UIApplicationDelegate * appDelegate = [[UIApplication sharedApplication] delegate];
if ([appDelegate respondToSelector:#selector(goToFirstTabBarWithData:)])
{
[appDelegate performSelector:#selector(goToFirstTabBarWithData:) withObject: strData];
}
}
In your Appdelegate :
- (void)goToFirstTabBarWithData:(NSString *)data
{
self.tabBarController.selectedIndex = 0;
UIViewController * vc = [self.tabBarController.viewControllers objectAtIndex:0];
if ([vc respondToSelector:#selector(setStringData:)])
{
[vc performSelector:#selector(setStringData:) withObject:data];
}
}
In your second View controller (the one you will arrive on) :
- (void)setStringData:(NSString *)data
{
// Do something...
}
I found a simpler solution to my problem. Inside of ViewControllerTwo, I just create an instance of ViewControllerOne and pass it that data I need. Then I change the tabBarController index to ViewControllerOne.
For example:
// A method inside of ViewControllerTwo
ViewController *viewcontrollerOne = [ViewcontrollerOne alloc] init];
[viewcontrollerOne setStringData:str];
[viewcontrollerOne release];
self.tabBarController.selectedIndex = 0;
I used the default template provided by Apple with Core Data (managedObjectContext is in AppDelegate). At first I was including appdelegate.h in every classes I needed to use managedObjectContext, but I saw this was not the correct way to do it. Apple says it's better to only pass the context to other classes that need it and so on, so I ended up doing it that way. Thing is, it looks a bit "hackerish" the way I did it, and I'm wondering if there's a better option or my solution is correct.
My app is currently setup like that (here's a SS of my storyboard):
So my root window is a UITabBarController, and each tab is a UINavigationController that points to multiple UITableViewController/UIViewController.
Here is what I have in my Appdelegate to pass the managedObjectContext instance to 2 tabs:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UITabBarController *rootViewController;
UINavigationController *navigationController;
ItemsTableViewController *itemsTableViewController;
// Get the root window (UITabBarController)
rootViewController = (UITabBarController *)self.window.rootViewController;
// Get the second item of the UITabBarController
navigationController = [[rootViewController viewControllers] objectAtIndex:1];
// Get the first item of the UINavigationController (ItemsTableViewController)
itemsTableViewController = [[navigationController viewControllers] objectAtIndex:0];
itemsTableViewController.managedObjectContext = self.managedObjectContext;
// Get the third item of the UITabBarController (again ItemsTableViewController)
navigationController = [[rootViewController viewControllers] objectAtIndex:2];
// Get the first item of the UINavigationController (ItemsTableViewController)
itemsTableViewController = [[navigationController viewControllers] objectAtIndex:0];
itemsTableViewController.managedObjectContext = self.managedObjectContext;
return YES;
}
Everything works well, but having to call multiple times objectAtIndex to get to the right ViewController looks meh...
Anyone as a better solution?
Thanks!
You should look at using the prepareForSegue: method to pass your managedObjectContext to the other controllers.
Alternatively, you can subclass the tab bar controller and add the managed object context as a property, which you can then access from anywhere within your app provided the tab bar controller is also there.
Finally, if you are only ever going to use one context (i.e. no multi threads) you can always setup a CoreDataHelper class with a class method that returns your default context whenever you ask for it. To avoid importing the helper in every single class just add the helper to your precompiled header file (.pch) and let it also import the <CoreData/CoreData.h> framework.
If you want to see an example of how this is done, checkout MagicalRecord on github https://github.com/magicalpanda/MagicalRecord
[EDIT]
Here's an example of how you would pass the context using the prepareForSegue method. Remember that this method is called when a segue is about to initiate and it gives you the opportunity to setup the view controller that is about to be pushed. This is where you could pass delegate references and assign values to other variables in your destination view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString *segueIdentifier = [segue identifier];
if ([segueIdentifier isEqualToString:#"YourSegueIdentifier"]) // This can be defined via Interface Builder
{
MyCustomViewController *vc = [segue destinationViewController];
vc.managedObjectContext = self.managedObjectContext;
}
}
Im working off the seismic xml iphone example.
In that example there is simply the application delegate which has a rootViewController of type UITableViewController.
I wanted to modify it slightly so that I would have a navigationController and use its rootViewController as the table view. My root view controller class for my navigation controller is named "firstLevelViewController"
In the sample code it says
[rootViewController.tableView reloadData];
I want to say [navController.firstLevelViewController.tableView reloadData]
but I get errors saying "request for member firstLevelViewController in something is not a structure or union"
How can I reference the rootViewController of the navigationcontroller from the main app delegate?
There isn't a firstLevelViewController property in a UINavigationController. If you want to access the current controller you can use
UITableViewController* firstLevelViewController = navController.topViewController;
assert([firstLevelViewController isKindOfClass:[UITableViewController class]]);
[firstLevelViewController.tableView reloadData];
If firstLevelViewController means the view controller at the bottom you can use
UITableViewController* firstLevelViewController = [navController.viewControllers objectAtIndex:0];
....
Access the rootViewController like this:
Objective-C
YourViewController *rootController =(YourViewController*)[[(YourAppDelegate*)
[[UIApplication sharedApplication]delegate] window] rootViewController];
Swift
let appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
let viewController = appDelegate.window!.rootViewController as YourViewController