iOS - reference active storyboard view controller from external class - ios

I'm really new to Objective C and I've got an application with a storyboard with a ViewController with the MyViewController class. I then have CDVPlugin (for my cordova application). From one of the methods in my cordova application I want to be able to reference the Active ViewController and call one of the functions from it. I have imported the MyViewController.h header and I was thinking maybe there is a way to make one a delegate for the other but I feel like this is the wrong way to approach this?
Any ideas?

You can get the current root view controller for the application using:
[UIApplication sharedApplication].delegate.window.rootViewController
The root view controller might be the active view controller, or it might be a navigation controller, in which case you might want something like:
UIViewController *active = ((UINavigationController *)[UIApplication sharedApplication].delegate.window.rootViewController).visibleViewController
if [active isKindOfClass: [MyViewController class]] {
MyViewController *myViewController = (MyViewController *)active
// Call any methods you need to on myViewController
}

Related

How to access parent view controller if there is container view inbetween?

How can I access Tab VC from rightmost VC(black)? I tried to use parentViewController from it but got nil.
I'm not a great fan of Containers, they really slow down the storyboard management in XCode.
You should be able to achieve the same result by turning all containers in simple views with a common IBOutlet to some kind of BaseViewController (you should always extend your custom BaseViewController instead of UIViewController in your classes, it gives you more flexibility for common features. Maybe you're already doing it :) ).
Then you can create a custom segue class with a perform method like this
-(void) perform {
BaseViewController* source = (BaseViewController*) self.sourceViewController;
UIViewController* destination = self.destinationViewController
[source.containerView addSubview:destination];
[source addChildViewController:destination];
//Custom code for properly center the destination view in the container.
//I usually use FLKAutolayout for autolayout projects with something like this
//[destination.view alignToView:source.view];
}
Draw a manual segue for the parent view controller to the "contained" view controller an give it a common identifier (something like "containerSegue").
Then in each view container view controller viewDidLoad method add:
[self performSegueWithIdentifier:#"containerSegue" sender:self];
and you should be in the same situation as before.
The only difference is that you can tweak the CustomSegue by adding custom properties and configuration for destination view controller. And, thanks to addChildViewController, your child VC should now have a parentViewController.
And, most of all, your storyboard should be REALLY smoother and faster to load in XCode.
Try this in rootViewController,
rootViewController.h
#interface rootViewController: UIViewController
{
}
+ (UIViewController *) sharedRootViewController;
#end
rootViewController.m
#import "rootViewController.h"
#implementation rootViewController
+ (UIViewController *) sharedRootViewController
{
return (UIViewController *)((UIWindow *)[[[UIApplication sharedApplication] windows] objectAtIndex:0]).rootViewController;
}
- (void) viewDidLoad
{
}
.
.
.
#end

Accessing tableViewController from appDelegate after adding SWRevealViewController

I have an app which displays a simple tableview and I wanted to add the SWRevealViewController as well.
In my appDelegate, before I added the SWReveal VC, I was setting my tableViewController like so...
In didFinishLaunchingWithOptions:
STRTableViewController *tableViewController = [(UINavigationController *)self.window.rootViewController viewControllers][0];
self.delegate = tableViewController;
and then again in the below method:
- (void)loadTableViewData
{
UINavigationController *navVC = (UINavigationController *)self.window.rootViewController;
STRTableViewController *tableVC = navVC.childViewControllers[0];
[tableVC loadTableData]
}
Obviously when I put the SWRevealViewController to the front of the line, this no longer works as it is now trying to call loadTableData from the wrong view controller.
I've tried several ways and keep coming up short. How do I go about accessing the tableViewController now that it is not the first view controller?
If you need more code or logs or anything I'll be happy to post additional info. I have a feeling the answer is right there, I just don't have the experience to see it.
Also, just to be clear, now in the storyboard it goes from Reveal View Controller to Navigation Controller (the tableview's nav VC/ sw_front) and also to the sw_rear VC. Before it simply started with the Navigation Controller.
Thanks!
There's a bunch of ways you can go about keeping a reference to this.
The simplest would be just to keep a reference to the view controller in the AppDelegate.m
So you add a property
#property (nonatomic, strong) STRTableViewController *tableViewController;
Then, whenever and wherever you are instantiating and setting that table view controller, just do something like:
AppDelegate *delegate = [[UIApplication sharedApplication] delegate];
delegate.tableViewController = justCreatedTableViewController;
You'll need to #import "AppDelegate.h" to access the app delegate in other classes where you want to do this.
Then to access it you can just do something like:
- (void)loadTableViewData
{
[self.tableViewController loadTableData]
}

Send UITableView row From One tableviewController to another

I want to send a UITableViewCell at indexPath.row from one controller to another. I can remove the row using removeObjectAtIndex, but unable to send the removed row into another controller.
I'm trying to store the removed row in an NSMutableArray in one controller, but don't know how to populate it in another controller.
Below is the code -
ViewController *view= [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
view.anotherviewArray= [self.arrayFromAFNetworking objectAtIndex:indexPath.row];
If anyone can give me an idea, it would be helpful.
I believe it's bad practice to retain UI elements and pass them around your app. You should instead have some kind of a model containing your data, and pass this model from one view controller to the other. I'd recommend checking out tableview frameworks such as the free Sensible TableView framework, as they do an excellent job of providing such a model for you automatically.
I personally think that it's wrong approach to pass UI object as parameter to another controller.
As I would do it is create some object that encapsulates data model from this cell and pass this object to another view controller.
#interface DataObject : NSObject
#property id field1;
#end
UI part of cell can be easily copied in Interface Builder, so I don't see problem in that. Probably it would be great to have cell class that could fill necessary field from the object with data. This class you can use in both view controller that have to show the same cell
#interface CustomTableViewCell : UITableViewCell
- (void)customizeCellWithDataObject:(DataObject *)dataObject;
#end
I hope it makes sense to you
Assuming that you DO want to set the other data source with only this row, you need to pass it as an array.
view.anotherviewArray= [NSArray arrayWithObject:[self.arrayFromAFNetworking objectAtIndex:indexPath.row]];
But it's hard to tell from the little code that you have provided. I assume that since you are instantiating the viewController you are also transitioning to it below the provided code. If you are trying to set the array for a viewController already presented, you need to access that one, not create another, perhaps by having saved a reference to it an ivar within the current viewController or another accessible class.
I would also not name a ViewController view, it is confusing to anyone reading the code later on.
Editing for my comment below about traversing the hierarchy. Here is some code that I used in one iPad project to return the final presented viewController. This method is in the appDelegate. It is somewhat specific to my project, where there is only one navigationController. But you can adapt it to yours. You would test for a viewController that is of the class of your target view controller.
- (UIViewController *)topViewController {
UIViewController *rootViewController = self.window.rootViewController;
UIViewController *topViewController = rootViewController.presentedViewController;
while (topViewController && topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
if ([topViewController isKindOfClass:[UINavigationController class]]) {
UIViewController *presentedViewController = [(UINavigationController *) topViewController topViewController];
if (presentedViewController) {
topViewController = presentedViewController;
}
}
}
return topViewController;
}
The other approach is to set a property to it when it is created and presented. We don't have enough code to get a good idea of your app as a whole. Where are you creating the ViewController instance that you are displaying? By that I mean where you are calling a segue to it, or pushing it onto a navigationController or call presentViewController. Wherever that is, you need to set a property or ivar to it. Let's say that you use a property in your appDelegate as a very generic case.
In your MyAppDelegate.h file you have
#property(nonatomic,strong) ViewController *viewController;
Wherever you first create it you set that property
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
I now think you are trying to add this to a mutableArray in the other ViewController. Then replacing your code from the tableViewCell above you would use
MyAppDelegate appDelegate = (MyAppDelegate)[[UIApplication sharedApplication] delegate];
[appDelegate.viewController.mutableDataArray addObject:self.arrayFromAFNetworking objectAtIndex:indexPath.row];
[appDelegate.viewController.tableView reloadData];
I will say that it is not great practice to use the appDelegate for the property. But it is a generic answer that would work. It's best to put it in a class which is common to the viewControllers that you are passing data between. Perhaps a single parent which holds these two viewControllers?

How to add a new custom UIViewController in IOS

I'm a new guy in this field
and i have a problem when i addSubView in AppDelegate
i have a Custom Controller look like this:
#interface mainViewController : UIViewController <UITableViewDelegate>
{
UITabBarController *myTad;
UITableView *myTable;
aModel *myModel
// ......
}
//Some methods and #property
All i want is make a View Controller that gets other Controller also connect to the model.
this is the place work all the things
and in AppDelegate i added in proper way.
[window addSubview: myController.view];
[window makeKeyAndVisible];
return YES
but its just didn't work ?
The Problem is loadView, the method i overWrite in mainViewController implement not do anythings. It's just go through
didn't i miss something?
You need to push your new view controller onto the stack, like so:
[self.navigationController pushViewController:myController];
Use a UINavigationController to control and 'connect' your views. This will allow you to push them properly and navigate back via back button.

Xcode Storyboard with a UITabViewController - change tabs from button

I've got a project setup using a Storyboard that contains a UITabViewController as the initial root view. One of the tabs loads a NavigationController that in turn loads a custom view controller class.
From the custom view controller, I have a navigation bar button that I want to trigger an action that returns the root UITabViewController to it's first index. I've been able to do this using a traditional xib structure by adding the appDelegate class to the xib and linking a method to the button that way.
Effectively, I want the button to trigger code that looks something like this:
#implementation AppDelegate
#synthesize window = _window;
#synthesize tabBarController=_tabBarController;
-(IBAction)handleHome:(id)sender{
//How do I send a message to the tabBarController?
[self.tabBarController setSelectedIndex:0];
}
Is it possible to do this with the Storyboard approach? I looked at Segue's but that doesn't seem to be what I'm trying to do (there is no way for me to talk to the root UITabViewController from what I can see).
I've got the handeHome method being triggered using the Responder approach, so really all I need to know is how to access the instantiated tabViewController in the Storyboard.
Hopefully this question makes sense, let me know if there is anything I should expand on.
Why not just do this in your custom view controller?
- (IBAction)handleHome:(id)sender {
self.tabBarController.selectedIndex = 0;
}
The tabBarController property is built in to UIViewController.
I figured it out. I updated the quoted block of code to this:
#implementation AppDelegate
#synthesize window = _window;
-(IBAction)handleHome:(id)sender{
UITabBarController *tabViewController = (UITabBarController *) self.window.rootViewController;
[tabViewController setSelectedIndex:0];
}
Sigh... need more coffee before asking questions on SO

Resources