Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIPageViewController and removing current view controller

I setup UIPageViewController to forward and backward through some view controllers . I have a problem which is when a view controller adds to UIPageViewController the memory usage will increase until the compiler gives me Received memory warning and then app runs too slowly until the app empties the memory and works fine again . How can I navigate through view controllers without increasing memory ? or better to say how can remove current view controller when a new on adds . here is my code :

// Create the page view controller.
self.pageViewController = [self.storyboard instantiateViewControllerWithIdentifier:@"PageViewController"];
self.pageViewController.dataSource = self;


//disabling tap and swipe guesture
for (UIGestureRecognizer *recognizer in self.pageViewController.gestureRecognizers) {
    recognizer.enabled = NO;
}


// Instantiate the first view controller.
UIViewController *startingViewController = [self viewControllerAtIndex:0];

[self.pageViewController setViewControllers:@[startingViewController]
                                  direction:UIPageViewControllerNavigationDirectionForward
                                   animated:NO
                                 completion:^(BOOL finished) {
                                     // Completion code
                                 }];

// Add the page view controller to this root view controller.
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
[self.pageViewController didMoveToParentViewController:self];

Forward and Backward actions :

- (void)goToPreviousContentViewController
{

    // Get index of current view controller
    UIViewController *currentViewController = [self.pageViewController.viewControllers objectAtIndex:0];
    NSString *vcRestorationID = currentViewController.restorationIdentifier;
    NSUInteger index = [self.contentPageRestorationIDs indexOfObject:vcRestorationID];

    UIViewController *previousViewController = [self viewControllerAtIndex:index - 1];



    [self.pageViewController setViewControllers:@[previousViewController]
                                      direction:UIPageViewControllerNavigationDirectionReverse
                                       animated:NO
                                     completion:^(BOOL finished) {
                                         // Completion code
                                     }];
}

More Codes :

#pragma mark - UIPageViewControllerDataSource
- (NSInteger)presentationCountForPageViewController:(UIPageViewController *)pageViewController
{
    return self.contentPageRestorationIDs.count;
}





- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerBeforeViewController:(UIViewController *)viewController
{
    NSString *vcRestorationID = viewController.restorationIdentifier;
    NSUInteger index = [self.contentPageRestorationIDs indexOfObject:vcRestorationID];

    if (index == 0) {
        return nil;
    }

    return [self viewControllerAtIndex:index - 1];
}




- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController viewControllerAfterViewController:(UIViewController *)viewController
{
    NSString *vcRestorationID = viewController.restorationIdentifier;
    NSUInteger index = [self.contentPageRestorationIDs indexOfObject:vcRestorationID];

    if (index == self.contentPageRestorationIDs.count - 1) {
        return nil;
    }

    return [self viewControllerAtIndex:index + 1];
}






#pragma mark - Private Methods
- (UIViewController *)viewControllerAtIndex:(NSUInteger)index
{
    // Only process a valid index request.
    if (index >= self.contentPageRestorationIDs.count) {
        return nil;
    }

    // Create a new view controller.
    BaseContentViewController *contentViewController = (BaseContentViewController *)[self.storyboard instantiateViewControllerWithIdentifier:self.contentPageRestorationIDs[index]];

    // Set any data needed by the VC here
    contentViewController.rootViewController = self;

    return contentViewController;
}
like image 948
iOS.Lover Avatar asked Sep 30 '15 16:09

iOS.Lover


People also ask

How do I remove a view controller from storyboard?

To delete the View Controller from the storyboard, select the View Controller by clicking the Show Document Outline icon and then clicking on View Controller Scene in the Document Outline. Then press Backspace or choose Edit > Delete.

How do I switch between view controllers?

Right-click the control or object in your current view controller. Drag the cursor to the view controller you want to present. Select the kind of segue you want from the list that Xcode provides.

What is PageView controller?

A controller for PageView. A page controller lets you manipulate which page is visible in a PageView. In addition to being able to control the pixel offset of the content inside the PageView, a PageController also lets you control the offset in terms of pages, which are increments of the viewport size.


2 Answers

To answer your questions

  1. "How can I navigate through view controllers without increasing memory?":

    You can't really do that. When you load a new view controller it will load all of it views and the view controller is stored in memory. You can't load and display a view controller that is not in memory.

  2. "How can remove current view controller when a new on adds":

    You shouldn't do that. An empty view controller doesn't have a big memory footprint, you can easily have 20+ view controllers in the navigation stack without any memory problem. Although it is possible to implement something like this, it takes a lot of work, and it doesn't solve the root of your problem.

What is the problem then?

You have a memory management problem. It is not caused by the code you have posted, that looks fine. The problem must be in another part of your code.

There are two common cases that could cause memory management issues:

  1. Retain cycles: A retain cycle is essentially when two objects retain each other. This goes against the standard rules of object ownership, leaving both objects with no authority to release the other, causing a memory leak (the numbers are the retain count):

  2. Unnecessary caching: If you are downloading a lot of different images and caching them, that is not the ideal use case for caching. Caching is ideal for storing frequently accessed objects. If you are not frequently accessing these images or receive a didReceiveMemoryWarning message, you should release these objects.

How can you debug memory issues

The first and most simple thing to do is to override the view controller's dealloc method. Overriding the dealloc method on a viewcontroller will help ensure that a viewcontroller is being deallocated when you expect it to be.

-(void)dealloc {
    NSLog(@"viewcontroller is being deallocated");
 }

If this doesn't help you can try to isolate the problem and debugging it with Xcode Instruments. This article could be a good start for you.

like image 62
Istvan Avatar answered Oct 14 '22 08:10

Istvan


To avoid memory and manage view controllers you need to stack all view controllers in a container.

So that every next/previous call will be made on that container and it will provide as your need. Also one more benefit of this container is to avoid reinitialise controller again and again.

Once you add view controller in container you are no need to alloc init or initialise that controller second time.

It's a big code to paste here and also storyboard setup will not be seen. So i share you one demo to visualise and use page controller with container to hold view controllers.

PageDemo

enter image description here

like image 40
Kampai Avatar answered Oct 14 '22 07:10

Kampai