iOS:UIScrollView中具有多个UIViewController的内存管理

iOS:UIScrollView中具有多个UIViewController的内存管理,ios,uiviewcontroller,uiscrollview,Ios,Uiviewcontroller,Uiscrollview,我有一个关于启用分页的UIScrollView的问题,它包含许多UIView,每个UIView都由自己的UIViewController管理 目前大约有20到30个UIViewController可以包含在UIScrollView中。这是iPad上的一个目录应用程序,我开始预装所有视图,但随着UIViewController的数量越来越大,这不再是一个选项 我正在寻找内存使用方面的完美解决方案。当ScrollView的ContentOffset到达特定控制器时,重新加载UIViewControl

我有一个关于启用分页的UIScrollView的问题,它包含许多UIView,每个UIView都由自己的UIViewController管理

目前大约有20到30个UIViewController可以包含在UIScrollView中。这是iPad上的一个目录应用程序,我开始预装所有视图,但随着UIViewController的数量越来越大,这不再是一个选项

我正在寻找内存使用方面的完美解决方案。当ScrollView的ContentOffset到达特定控制器时,重新加载UIViewController没有问题。我认为当ContentOffset告诉我不再需要UIViewController时,取消UIViewController也不是那么难

正确的处理方法是什么?在需要时分配UIViewController,将其放入NSMutableDictionary或NSMutableArray中,在不再需要时将其置零,这样是否足够?从已经做过类似工作的人那里得到一点帮助将是非常棒的


谢谢你的帮助

我肯定有一些很好的无限滚动类,但是如果你想“滚动你自己的”,这里有一段最简单的代码,演示无限滚动的过程,将当前、上一页和下一页保留在内存中,但放弃其他任何内容。这假定:

  • 您正在进行水平滚动并已打开分页
  • 您正在为子视图使用视图控制器
  • 您的子视图控制器类有一个
    页面
    属性来跟踪它用于哪个页面;及
  • 您已将视图控制器设置为滚动视图的代理
因此,它可能看起来像:

- (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];
}
-(void)viewDidLoad
{
[超级视图下载];
//我的底层模型只是一个字符串数组,我将在我的孩子身上显示它
//视图;您的模型将更加详细,但我只想说明这个概念
self.objects=@[“1”、“2”、“3”、“4”、“5”、“6”、“7”、“8”、“9];
//为scrollview设置“contentSize”
CGRect content=self.view.bounds;
content.size.width*=[self.objects count];//使其足够宽以容纳所有内容
self.scrollView.contentSize=content.size;
//设置当前页面并加载第一页(第一页和下一页)
self.currentPage=0;
[self addChildPage:0到scrollView:self.scrollView];
[self addChildPage:1到scrollView:self.scrollView];
}
-(void)添加子页面:(NSInteger)页面到滚动视图:(UIScrollView*)滚动视图
{
//创建子控制器
ChildViewController*控制器=[self.storyboard实例化eviewcontrollerwhiteIdentifier:@“child”];
//设置所需的任何属性,以使其正确显示其信息
controller.text=self.objects[页面];
controller.page=page;
//现在做一些事情,将其添加到scrollview中的正确位置
CGRect frame=self.view.bounds;
frame.origin.x=frame.size.width*页;
controller.view.frame=frame;
[self-addChildViewController:controller];//用于添加子视图控制器的包含调用
[scrollView添加子视图:controller.view];
[controller-didMoveToParentViewController:self];//添加完子级后的包含调用
}
-(ChildViewController*)ChildControllerFormage:(NSInteger)第页
{
用于(self.childViewControllers中的ChildViewController*控制器)
{
如果(controller.page==第页)
返回控制器;
}
返回零;
}
-(void)添加childifneeded:(NSInteger)页面到scrollView:(UIScrollView*)滚动视图
{
如果(第<0 | |页>=[self.objects count])
返回;
ChildViewController*控制器=[self ChildControllerFormage:page];
如果(控制器==nil)
[自添加子页面:页面到滚动视图:滚动视图];
}
-(void)移除ChildController:(UIViewController*)控制器
{
[控制器willMoveToParentViewController:nil];//删除子级之前的包含调用
[controller.view removeFromSuperview];
[controller removeFromParentViewController];//删除子对象的包含调用
}
-(void)updateChildrenViewsForPage:(NSInteger)用于scrollView:(UIScrollView*)滚动视图的页面
{
如果(页面==self.currentPage)
返回;
//根据需要添加子页面
[self-addChild(如有必要):页面到滚动视图:滚动视图];
[如有必要,可自行添加儿童:(第1页)至滚动视图:滚动视图];
[self addChild(如有必要):(第+1页)至滚动视图:滚动视图];
//查找任何需要删除的页面
NSMutableArray*pagesToRemove=[NSMutableArray];
用于(self.childViewControllers中的ChildViewController*控制器)
{
如果(controller.page<(第1页)||
controller.page>(第+1页))
{
[pagesToRemove addObject:控制器];
}
}
//如果需要移除,请移除它们
用于(UIViewController*pagesToRemove中的控制器)
{
[self-removeChildController:controller];
}
//更新我们的“当前页面”索引
self.currentPage=page;
}
-(无效)scrollViewDidScroll:(UIScrollView*)scrollView
{
NSInteger page=scrollView.contentOffset.x/scrollView.frame.size.width+0.5;
[self-updateChildrenViewsForPage:page for scrollView:scrollView];
}

这演示了适当的自定义容器调用和滚动事件的处理。我希望这会有所帮助。

我肯定有一些很好的无限滚动类,但是如果你想“滚动你自己的”,这里有一段最简单的代码,演示无限滚动的过程,将当前、上一页和下一页保留在内存中,但不涉及其他任何内容。这假定: