Im using a page based application very similar to the standard template from apple (page based app). I want all the pages to be loaded and kept in memory at start up, but it doesnt work. I keep all the ViewControllers that UIPageViewController displays in an NSArray which I initiate. The problem is that the ViewControllers are not initilized until the PageViewController calls them. How do I force initiation of ViewControllers right here in the init method of the ModelController.
- (id)init
{
self = [super init];
if (self) {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *historyViewController = [storyboard instantiateViewControllerWithIdentifier:#"HistoryViewController"];
historyViewController.restorationIdentifier= HistoryRestorationID;
UIViewController *totalViewController = [storyboard instantiateViewControllerWithIdentifier:#"TotalViewSlidingController"];
totalViewController.restorationIdentifier= TotalRestorationID;
PlugTableViewController *plugViewController = [storyboard instantiateViewControllerWithIdentifier:#"PlugSlidingViewController"];
plugViewController.restorationIdentifier= PlugRestorationID;
//Force initiation of ViewController here!
pages = [[NSArray alloc] initWithObjects:historyViewController,totalViewController,plugViewController, nil];
}
return self;
}
The reason why I want to initiate them directly, is because they take time to initiate.
The view hierarchy is not loaded until someone references its view property.
Try call [historyViewController view] or read historyViewController.view. It should do the job.
Try type-casting the object where you want to use this view, hopefully this will do the job.
PlugTableViewController *plugView=(PlugTableViewController *)[pages objectAtIndex:3];
And one more things, try to change the code
UIViewController *historyViewController = [storyboard instantiateViewControllerWithIdentifier:#"HistoryViewController"];
to
HistoryViewController *historyViewController = [storyboard instantiateViewControllerWithIdentifier:#"HistoryViewController"];
hopefully you have made a header class HistoryViewController but you are initlizing view by UIViewController
Another possible solution is to pre-load data instead of viewcontroller as view controller do not take time to load.
MOST UNRECOMMENDED way is to add all view as subview and keep them hidden, show them when you need them.
Related
I am trying to access an Array variable in a view controller in an application that is using storyboards.
BACKGROUND:
I have been following along with the Ray Wenderlich tutorial on Storyboards.
Once I finished the tutorial, I went back tried a different route, though I’m having trouble accessing a view controller. Everything is pretty much the same except my set up is the initial Scene is a View Controller. I am to the part where the author is adding some data to NSMutableArray in his table.
THEIR CODE THAT I AM USING AS A GUIDE
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UINavigationController *navigationController = [tabBarController viewControllers][0];
PlayersViewController *playersViewController = [navigationController viewControllers][0];
playersViewController.players = _players;
I was hoping it would be a simple as replicating what I had seen with view controllers, passing along the appropriate type, but no.
I have View Controller > View Controller > Navigation View Controller > UITableViewController.
MY CODE:
UIViewController *vc = (UIViewController*)self.window.rootViewController;
UIViewController vc1 = [vc viewController][0];
UINavigationController *nc = [vc1 viewController][0];
SearchViewTableViewController *svc = [nc viewControllers][0];
svc.myarray = _myarray;
I have tried multiple combinations and am getting nowhere.
There has got to be a simpler way for me to reference classes/view/scenes.
Any help?
Make sure you are importing the ViewController header file.
Make sure you have given you ViewController a Storyboard identifier.
Then something like this should work:
MyViewController *myVC = [[UIStoryboard storyboardWithName:#"Main" bundle:nil] instantiateViewControllerWithIdentifier:#"MyViewController"];
myVC.myMutableArray = [NSMutableArray new];
....
I have a UINavigationController in which I push several UIViewControllers.
I want that every time a new UIViewController is pushed, the older ones get released from memory.
For that, in every UIViewController I'm putting this piece of code:
-(void)viewDidAppear{
self.navigationController.viewControllers = #[self];
}
This way the viewControllers array gets reduced only to the one being displayed. But since I'm using ARC, every UIViewController is a strong reference and it's not being released from memory.
I've tried creating a weak instance of every UIViewcontroller when pushing them using this code:
FirstViewController.m
-(IBAction)goToSecond:(id)sender{
SecondViewController *secondVC = [[SecondViewController alloc]init];
__weak SecondViewController *weakSecondVC = secondVC;
[self.navigationController pushViewController:weakSecondVC animated:NO];
}
But this way I'm creating two instances: the weak one that is being pushed and the strong one that stays in memory.
I have also tried creating just the weak reference and pushing it:
FirstViewController.m
-(IBAction)goToSecond:(id)sender{
__weak SecondViewController *weakSecondVC;
[self.navigationController pushViewController:weakSecondVC animated:NO];
}
But then I get the following:
Application tried to push a nil view controller on target <UINavigationController: 0x127606210>.
Is there any way to achive this?
EDIT:
As suggested in the answer I've tried doing the following:
-(void)goToSecond:(id)sender{
SecondViewController *pistasVC = [[EYSPistasViewController alloc] init];
[self.navigationController setViewControllers: #[secondVC]];
[self.navigationController popViewControllerAnimated:NO];
}
The UINavigationController stack of UIViewController it's reduced to the one I'm setting, but the memory still keeps adding up.
Here you can see a comparison of both methods:
You can try this code to make navigation controller to contain only one viewController.
-(IBAction)goToSecond:(id)sender
{
SecondViewController *secondVC = [[SecondViewController alloc]init];
[self.navigationController setViewControllers:#[secondVC] animated:NO];
}
I've created an app that uses a bunch load of Container views. Today i've found out that embedded segues are not supported in iOS 5 (thanks Xcode for letting me know.)
So right now I have a lot of embedded segues that passes data between one another.
I'm using this code to load ViewControllers inside a UIView instead of the Container from the IB:
RootViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
NewsViewController *news = [storyboard instantiateViewControllerWithIdentifier:#"NewsViewControllerID"];
news.view.frame = self.newsSection.bounds;
[self.newsSection addSubview:news.view];
[self addChildViewController:news];
[news didMoveToParentViewController:self];
// Do any additional setup after loading the view.
}
How can I use the above and still pass data to NewsViewController (something like prepare for segue)
I've tried inserting in the above something like
NewsViewController *news = [storyboard instantiateViewControllerWithIdentifier:#"NewsViewControllerID"];
news.view.frame = self.newsSection.bounds;
news.myLabel.text = #"Test";
[self.newsSection addSubview:news.view];
But the label won't change.
I prefer just to pass the data and not use a singleton or delegation.
Thanks
I would recommend creating a public method, from where you could pass the data you need on your NewsViewController controller. Still, the issue right now is that the you are updating the UI before it has been initialised. Also I would recommend you to have a look on how to create content UIViewControllers, because right now you are only adding its UIView. Check this document from Apple, look at the section Implementing a Custom Container View Controller. And this part of the code:
- (void) displayContentController: (UIViewController*) content;
{
[self addChildViewController:content]; // 1
content.view.frame = [self frameForContentController]; // 2
[self.view addSubview:self.currentClientView];
[content didMoveToParentViewController:self]; // 3
}
So in your case, after the step 3 has been made, you could pass the values you want to use inside your NewsViewController.
The problem could be that at the moment you are setting the text of the label, the label is still nil.
Try adding an NSString property to your NewsViewController (e.g. labelText), and in viewDidLoad do self.myLabel.text = self.labelText;.
you have pass the string your next view controller and viewDidLoad you have to the string.
Its not working because your view not yet created and if check the instance of UIlabel it will nil. So you have set the text in your next viewcontroller when it loaded in the memory.
Edit
you have create a property variable of NSString type(textString) in NewsViewController and pass the string as news.textString = #"Test";
and the in ViewDidLoad of NewsViewController set that string to label as myLabel.text = textString;
Better Explanation
-Declare NSString property in the NewsViewController.h
#property (strong, nonatomic) NSString *assignText;
-Instantiate normally, but assign the string and not the label.
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
NewsViewController *news = [storyboard instantiateViewControllerWithIdentifier:#"NewsViewControllerID"];
news.assignText = #"Test";
[self addChildViewController:news];
-Then in your NewsViewController viewDidload, assign the label to the string.
-(void)viewDidLoad {
[super viewDidLoad];
self.myLabel.text = self.assignText;
}
This question might have been answered, if yes, please share the link.
I have created a Single View Application, It works fine, but now I have added a new view and on a button click, wants the new view to appear.
This is the code for click action,
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self.navigationController pushViewController:settingsViewController animated:YES];
The Default ViewController now looks like this in .h file
#interface ViewController : UIViewController<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
The SettingsViewController.m has a default
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{}
Can I add another view to "Single View Application" like this or should I chose another template for my project ?
Thanks.
You need to create a UINavigationController in your AppDelegate. Then make your ViewController the rootViewController of the UINavigationController. Then you will be able to push and pop views.
Here is the code to create the rootViewController where mainNavigationController is the UINavigationController in your AppDelegate:
ViewController *vc = [[ViewController alloc] init];
mainNavigationController = [[UINavigationController alloc] initWithRootViewController:vc];
Once you have the ViewController set up as the rootViewController it will conform to the UINavigationController push and pop methods to create a stack of UIViewControllers.
That is fine. The single view application template is just a barebones template. You can add any type of navigation you like to it.
In iOS 5, switching between views works a bit different i think,
I have created a few apps with the above mentioned code for switching views.
But now, I have to write it like this to work:
SettingsViewController *settingsViewController = [[SettingsViewController alloc] initWithNibName:#"SettingsViewController" bundle:[NSBundle mainBundle]];
[self presentModalViewController:settingsViewController animated:YES];
I've been pulling my hair out trying to get a basic NavigationController working that will allow me to switch back and forth between views easily. I feel like I'm making progress, but I'm clearly missing something critical. I now have my template app pushing views, but only by adding the initWithNibName pointing to the target NIB. Attempting to add any functionality to these secondary views causes the app to crash with a SIGABRT error. I can't imagine this is right.. If I simply have a plain NIB, the switch works fine. The only thing I've added to the secondViewcontroller is a label and a button to populate the label with some garbage text. Yet the instant I hit the switch button to shift push this view i get the SIGABRT. I'd like to be able to put functionality within the different view controllers. I feel like i'm so close, but tis is so aggravating. Can anyone point out where i've gone wrong?
#import "mainViewController.h"
#implementation mainViewController
-(void)switchView {
UIViewController *secondViewController = [[UIViewController alloc] initWithNibName:#"secondViewController" bundle:nil];
secondViewController.title = #"My First View";
[self.navigationController pushViewController:secondViewController animated:YES];
[secondViewController release];
}
-(void)switchViewTwo {
UIViewController *thirdViewController = [[UIViewController alloc] initWithNibName:#"thirdViewController" bundle:nil];
thirdViewController.title = #"My second View";
thirdViewController.view.backgroundColor = [UIColor redColor];
[self.navigationController pushViewController:thirdViewController animated:YES];
[thirdViewController release];
}
Instead of
UIViewController *secondViewController = [[UIViewController alloc] initWithNibName:#"secondViewController" bundle:nil];
Put this:
MySecondViewController *secondViewController = [[MySecondViewController alloc] initWithNibName:#"secondViewController" bundle:nil];
My MySecondViewController should be the name of your UIViewController, also check that the XIB's name is really called secondViewController. Finally:
Go to your XIB
Select the File's Owner file.
Select the 3rd tab in the inspector.
Check the name of the class. It should be MySecondViewController instead of UIViewController.