2013-03-25 2 views
1

У меня вопрос о UIScrollView с включенным пейджингом, который содержит много UIView, каждый из которых управляется собственным UIViewController.iOS: Управление памятью в UIScrollView с большим количеством UIViewControllers

В настоящее время существует около 20-30 UIViewControllers, которые МОГУТ содержать в UIScrollView. Это приложение для каталога на iPad, и я начал предварительно загружать все взгляды в начале, но с увеличением количества UIViewControllers все больше и больше не является вариантом.

Я ищу идеальное решение с точки зрения использования памяти. Не нужно перезагружать UIViewControllers, когда ContentOffset ScrollView достигает определенного контроллера. И я думаю, что NIV UIViewControllers, когда ContentOffset говорит мне, что UIViewControllers больше не нужны, не так сложно.

Каков правильный способ справиться с этим? Достаточно ли распределять UIViewControllers по мере необходимости, помещая их в NSMutableDictionary или NSMutableArray и nil их, когда они больше не нужны? Немного помочь от кого-то, уже сделавшего что-то подобное, было бы здорово!

Благодарим за помощь!

+0

Ваш дизайн неправильный. Вы не должны «помещать» UIViewControllers в scrollView. – Petar

+0

Я не помещаю UIViewControllers в UIScrollView, я помещаю UIViewControllers UIView в UIScrollView. – chritaso

+0

Конечно, это то, что я имею в виду, и вы не должны этого делать. Постарайтесь сделать так, чтобы у вас было только 1 контроллер вида, который управляет представлениями, хранящимися в scrollView. – Petar

ответ

3

Я уверен, что есть некоторые хорошие бесконечные классы прокрутки, но если вы собираетесь «сворачивать свои собственные», вот минималистский бит кода, который демонстрирует процесс бесконечной прокрутки, сохраняя текущий, предыдущий , и следующие страницы в памяти, но отпускать что-нибудь еще. Предполагается, что:

  • вы делаете горизонтальную прокрутку и включили пейджинг;
  • что вы используете контроллеры представлений для дочерних видов;
  • ваш класс контроллера дочернего класса имеет свойство page, чтобы отслеживать, на какой странице он предназначен; и
  • вы сделали свой контроллер представления делегата для прокрутки зрения

Таким образом, это может выглядеть следующим образом:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    // my underlying model is just an array of strings, which I'll show on my child 
    // view; your model will be more elaborate, but I just want to illustrate the concept 

    self.objects = @[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9"]; 

    // set the `contentSize` for the scrollview 

    CGRect content = self.view.bounds; 
    content.size.width *= [self.objects count]; // make it wide enough to hold everything 
    self.scrollView.contentSize = content.size; 

    // set our current page and load the first pages (the first and the next pages) 

    self.currentPage = 0; 
    [self addChildPage:0 toScrollView:self.scrollView]; 
    [self addChildPage:1 toScrollView:self.scrollView]; 
} 

- (void)addChildPage:(NSInteger)page toScrollView:(UIScrollView *)scrollView 
{ 
    // create the child controller 

    ChildViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:@"child"]; 

    // set whatever properties you need to in order for it to present its information correctly 

    controller.text = self.objects[page]; 
    controller.page = page; 

    // now do the stuff to add it to the right place in the scrollview 

    CGRect frame = self.view.bounds; 
    frame.origin.x = frame.size.width * page; 
    controller.view.frame = frame; 
    [self addChildViewController:controller];  // containment call for adding child view controller 
    [scrollView addSubview:controller.view]; 
    [controller didMoveToParentViewController:self]; // containment call when done adding child 
} 

- (ChildViewController *)childControllerForPage:(NSInteger)page 
{ 
    for (ChildViewController *controller in self.childViewControllers) 
    { 
     if (controller.page == page) 
      return controller; 
    } 

    return nil; 
} 

- (void)addChildIfNecessary:(NSInteger)page toScrollView:(UIScrollView *)scrollView 
{ 
    if (page < 0 || page >= [self.objects count]) 
     return; 

    ChildViewController *controller = [self childControllerForPage:page]; 

    if (controller == nil) 
     [self addChildPage:page toScrollView:scrollView]; 
} 

- (void)removeChildController:(UIViewController *)controller 
{ 
    [controller willMoveToParentViewController:nil]; // containment call before removing child 
    [controller.view removeFromSuperview]; 
    [controller removeFromParentViewController];  // containment call to remove child 
} 

- (void)updateChildrenViewsForPage:(NSInteger)page forScrollView:(UIScrollView *)scrollView 
{ 
    if (page == self.currentPage) 
     return; 

    // add child pages as necessary 

    [self addChildIfNecessary:page  toScrollView:scrollView]; 
    [self addChildIfNecessary:(page-1) toScrollView:scrollView]; 
    [self addChildIfNecessary:(page+1) toScrollView:scrollView]; 

    // find any pages that need removing 

    NSMutableArray *pagesToRemove = [NSMutableArray array]; 
    for (ChildViewController *controller in self.childViewControllers) 
    { 
     if (controller.page < (page - 1) || 
      controller.page > (page + 1)) 
     { 
      [pagesToRemove addObject:controller]; 
     } 
    } 

    // remove them if they need removing 

    for (UIViewController *controller in pagesToRemove) 
    { 
     [self removeChildController:controller]; 
    } 

    // update our "current page" index 

    self.currentPage = page; 
} 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView 
{ 
    NSInteger page = scrollView.contentOffset.x/scrollView.frame.size.width + 0.5; 

    [self updateChildrenViewsForPage:page forScrollView:scrollView]; 
} 

Это демонстрирует соответствующие вызовы пользовательских контейнеров и обработку прокрутки Мероприятия. Надеюсь, это поможет.

+2

Thank вы, Роб. Это действительно подробный ответ, который мне очень поможет! – chritaso

+0

Единственная проблема, с которой я сталкиваюсь сейчас, заключается в том, что контроллеры не освобождены правильно. Я не знаю, почему, но метод dealloc каждого контроллера вызывается, я нолю каждого представления, которому я занимаюсь, тем не менее все больше выделяется память. Может ли это быть проблема с анкером IBOutlet ...? – chritaso

+0

@chritaso Как вы это определили? Инструмент «Утечки» показывает вам утечки? (Если это так, вы можете посмотреть дерево вызовов и точно определить, что происходит, что является первым шагом в устранении утечки.) Или вы смотрите на инструмент «Выделения»? Некоторые люди ошибочно смотрят на «общие байты» (в том числе на вещи, которые были выпущены), но вы должны посмотреть «Live Bytes». – Rob

Смежные вопросы