How to improve efficiency with AddChildViewController - ios

I am using AddChildViewController and adding a CalendarViewController, here is the code to add it
- (void)calButtonClicked
{
m_calViewController = [[CalendarViewController alloc]initWithNibName:#"CalendarViewController" bundle:nil];
[self addChildViewController:m_calViewController];
[[self view] addSubview:[m_calViewController view]];
[m_calViewController didMoveToParentViewController:self];
}
Now this CalendarViewController I have a function to create the calendarUI , I have written it in
- (void)viewDidLoad
{
[self createCalendarUI];
}
Now whenever I click on the button to open this ViewController , method viewDidLoad is called everytime and it takes time to create the UI. And because of that , my app is becoming slow.
So is their any way so that my UI is created only once, So that I can improve the efficiency
Regards
Ranjit.

if you just want to reuse CalendarViewController
try reuse CalendarViewController's view and do not alloc CalendarViewController in calButtonClicked each time.
- (void)calButtonClicked
{
if(!m_calViewController){
m_calViewController = [[CalendarViewController alloc]initWithNibName:#"CalendarViewController" bundle:nil];
[self addChildViewController:m_calViewController];
}
[[self view] addSubview:[m_calViewController view]];
[m_calViewController didMoveToParentViewController:self];
}

Related

iOS: change view from viewDidAppear

I'm playing around with view life cycles & am having trouble changing a view from the load of a different view.
In my ViewController.h i have:
-(void)viewDidAppear:(BOOL)animated{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
}
However this only causes the view to be between ViewController, and ViewController2 appearing with animation (in a loop).
I used the code in viewDidLoad however neither of the view's loaded (from reading you cannot change view until the viewWillAppear)
Update: When using the code in viewWillAppear, whose view is not in the window hierarchy error is thrown.
How does one change the view from view setup stage?
Update
Using the above code, inside & out of GCD, in viewDidLoad, viewWillAppear & viewDidAppear either results in an infinite loop of animated showing of the ViewController2, or crash on 2nd attempt of segue (result from the loop).
EDITED:
I'm not sure exactly what you're trying to do, but assuming you are wanting the first viewcontroller to appear and then the second viewcontroller to immediately animate on top of the first one, you should be able to accomplish using several options:
First you could just wrap your calls in a dispatch_async call:
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard
instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
});
Or you could use a show modally segue:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"myModalSegue" sender:self];
});
}
Or you could use a navigation controller and use a standard show segue (formally push). This one doesn't require the dispatch_async:
- (void)viewDidLoad {
[super viewDidLoad];
[self performSegueWithIdentifier:#"myshowsegue" sender:self];
}
I've posted working examples of all three on: github
It is better to exchange views in loadView method.
- (void)loadView {
CGRect rect = [[UIScreen mainScreen] applicationFrame];
MyView *view = [[MyView alloc] initWithFrame:rect];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
self.view = view;
}

UIScrollView disabled after UINavigationController push and pop

I have looked at the other answers to this question, and none of them have helped.
I have a UIScrollView in my very simple scene, embedded like this:
I use this code to make sure the scroll view will actually scroll, based off of this answer.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self resizeScrollView];
}
- (void) viewDidLayoutSubviews {
[self resizeScrollView];
}
- (void)resizeScrollView
{
_scrollView.scrollEnabled = YES;
[_scrollView setContentSize:_innerView.frame.size];
}
- (IBAction)cameraButtonPressed:(id)sender {
UIViewController *vc = [UIViewController new];
[self.navigationController pushViewController:vc animated:YES];
}
The problem is that scrolling doesn't work after I've pushed and popped the new ViewController (Which originally was an image picker btw).
I don't know why this worked, but I wrapped everything in another view, and it's perfect now.

Containment and UITableView flashScrollIndicators

I currently have a Parent ViewController which contains a child UIViewController (Child). The child UIViewController has a UITableView. On Child.viewDidAppear I invoke the TableView.flashScrollIndicators.
For some reason the scroll indicators are not flashing. I've noticed if I put a dispatch_after call, the second pass does a flash. I thought at first it was a size issue, but I don't think that's it. It seems to be a layout issue (I'm using Storybards, iOS 7, and no AutoLayout). Any ideas?
Here's my code for creating the Child.
- (void)viewDidLoad {
[super viewDidLoad];
// add it to the heirarchy
if ([[self childViewControllers] count] == 0) {
[self setViewControllers:[[NSMutableArray alloc] init]];
ProductSelectionViewController *destination = (ProductSelectionViewController *)[[self storyboard] instantiateViewControllerWithIdentifier:#"ProductSelectionViewController"];
[self addChildViewController:destination];
// present the child
[destination didMoveToParentViewController:self];
[[self containerView] addSubview:[destination view]];
[[self viewControllers] addObject:destination];
[destination setDelegate:self];
}
}
For me, it worked to call
[self performSelector: #selector(flashScrollIndicators) withObject: nil afterDelay: 0];
instead of
[self flashScrollIndicators];
in didMoveToWindow method of the view or in viewDidAppear of its view controller. Hope this helps people with the same issue.

Possible to Preload a UIView that contains a library of information?

Is is possible to have a UIView preloaded so that it will load faster when the user taps on button to load it? Currently I've got a library of informaiton that I'm attempting to load when the user taps a button, and for now it seems to be "ok" , but it makes the navigation to the page choppy, because of all the information in the library it's loading.
Thanks in advance!
It should be possible to split the setup of a View Controller from code that displays the view after a button is pushed. This will eliminate the lag when the button but the task to setup the view controller still need to be done sometime during execution (You can for example put it in the ViewdidAppear method so it is executed while waiting for the button to be pushed.
Take this code for example:
-(IBAction) button_pushed {
/*setup */
NewVC *vc = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
/*display */
[self.navigationController pushViewController:vc animated:NO];
return;
}
You can split the code that setup the view from the code that displays the view
into :
#synthesize vc;
…..
- (NewVC) setup {
//setup
NewVC *vc1 = [[NewVC alloc] init];
vc.var1 = var1;
vc.var2 = x;
[vc setup];
return(vc1);
}
-(void) ViewDidAppear {
if (setupready) {
vc = [self setup];}
return;
}
-(IBAction) button_pushed:(ID) sender {
//display
[self.navigationController pushViewController:vc animated:NO];
return;
}

UIViewController removeFromSuperview error

I have a UIViewController then when I longpress to self.view it will push a popup (MenuViewController). But when I try to remove popup by removeFromSuperview it still appears
You can see more detail of my problem with this http://www.youtube.com/watch?v=nVVgmeJEnnY
ViewController.m
#import "MenuViewController.h"
#interface ViewController () {
MenuViewController *menu;
}
....
- (void)viewDidLoad
{
....
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(albumButtonPressed : ) name:#"albumButtonPressed" object:nil];
....
}
....
-(void)albumButtonPressed : (NSNotification*) notification {
UIImagePickerController *photoPicker = [[UIImagePickerController alloc] init];
photoPicker.delegate = self;
photoPicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentModalViewController:photoPicker animated:YES];
}
...
-(void)handleLongPress:(UILongPressGestureRecognizer*)recognizer {
menu = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
if (self.imageView.image != nil) {
menu.imageAdded = YES;
}
[self.view addSubview:menu.view];
}
MenuViewController.m
-(IBAction)albumButtonPressed:(id)sender {
[self.view removeFromSuperview];
[[NSNotificationCenter defaultCenter] postNotificationName:#"albumButtonPressed" object:nil];
}
Setting aside my reservations about not applying proper view controller containment, the problem is that your handleLongPress will be called multiple times with different recognizer.state values, once as UIGestureRecognizerStateBegan and again as UIGestureRecognizerStateEnded. You should be checking the state of the gesture, e.g.:
-(void)handleLongPress:(UILongPressGestureRecognizer*)recognizer {
if (recognizer.state == UIGestureRecognizerStateEnded) {
menu = [[MenuViewController alloc] initWithNibName:#"MenuViewController" bundle:nil];
if (self.imageView.image != nil) {
menu.imageAdded = YES;
}
[self.view addSubview:menu.view];
}
}
Original Answer:
I'd suggest putting a NSLog or breakpoint at your code with the removeFromSuperview and see if you're even getting to that piece of code.
There are some clear problems here. Specifically, you're not adding added the view associated MenuViewController in handleLongPress properly. If you want a subview with it's own controller, you have to use containment (and that only works with iOS 5 and later). And in containment, you have critical methods like addChildViewController, etc. See Creating Custom Container View Controllers in the View Controller Programming Guide or see WWDC 2011 - Implementing UIViewController Containment. And, as an aside, you're also maintaining a strong reference to MenuViewController, so even if you succeeded in removing it's view, you'd leak the controller.
Spend a little time going through the containment documentation/video, and I think you'll want to revisit how you're presenting your menu. This is dense reading, but worth really understanding. Containment is powerful, but has to be done right.
[self.view removeFromSuperview];
what do you mean by this?????? removing the main view!!!!
Instead of directly using
[self.view removeFromSuperview];
use
[[self.view.superview subviews] makeObjectsPerformSelector:#selector(removeFromSuperview) withObject:self.view];

Resources