释放scrollview中多个视图控制器的内存

时间:2012-10-29 09:33:52

标签: ios memory uiviewcontroller uitableview scrollview

我有一个应用程序在滚动视图中加载了许多视图控制器,具体取决于用户在tableview中的对象数量。因此,当我在tableview和滚动视图之间切换时,滚动视图中的视图控制器数量会根据用户在tableview中的对象数量而变化。

我使用Apple的PageControl示例代码中的代码构建滚动视图,其中包含许多视图控制器,当然经过一些修改。

- (void)loadScrollViewWithPage:(int)page 
{
   if (page < 0) return;
   if (page >= kNumberOfPages) return;

   // replace the placeholder if necessary
   MainViewController *countdownController = [viewControllers objectAtIndex:page];
   if ((NSNull *)countdownController == [NSNull null]) 
   {

      id occasion = [eventsArray objectAtIndex:page];

      countdownController = [[MainViewController alloc] initWithPageNumber:page];
      [countdownController setOccasion:occasion];

      [viewControllers replaceObjectAtIndex:page withObject:countdownController];


      [countdownController release];

    }

    // add the controller's view to the scroll view
    if (nil == countdownController.view.superview) 
    {
      CGRect frame = scrollView.frame;
      frame.origin.x = frame.size.width * page;
      frame.origin.y = 0;
      countdownController.view.frame = frame;
      [scrollView addSubview:countdownController.view];
    }

}

问题是当我在表视图和滚动视图(根据Instruments)之间切换时,生活视图控制器(MainViewController)的数量不断增加,即使我没有添加任何导致内存问题的新对象

我在滚动视图的viewWillDisappear中尝试了很多东西,如:

- (void) viewWillDisappear:(BOOL)animated
{


    //test unloading all views
    //Remove all subviews
    [[scrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

    //[[scrollView subviews] makeObjectsPerformSelector:@selector(release)];


    //[viewControllers removeAllObjects];
    for (unsigned m = 0; m < [viewControllers count]; m++)
    {
     //[[viewControllers objectAtIndex:m] makeObjectsPerformSelector:@selector(release)];

      [viewControllers removeObjectAtIndex:m];
    }
 }

但它没有用。 以下是应用程序的工作原理youtube.com/watch?v=5W8v_smZSog

这是滚动视图的viewWillAppear方法:

- (void)viewWillAppear:(BOOL)animated
{

    eventsArray = [[NSMutableArray alloc] init];

    kNumberOfPages = [self.dataModel occasionCount];

    //update the eventsArray from the dataModel
    //Fill in the events Array with occasions form the data model
    for (unsigned r = 0; r < kNumberOfPages; r++)
    {
        Occasion* occasion = [self.dataModel occasionAtIndex:r];
        [eventsArray insertObject:occasion atIndex:r];
    }

     // view controllers are created lazily
     // in the meantime, load the array with placeholders which will be replaced on   demand
    NSMutableArray *controllers = [[NSMutableArray alloc] init];
    for (unsigned i = 0; i < kNumberOfPages; i++)
    {
        [controllers addObject:[NSNull null]];
     }

    self.viewControllers = controllers;
    [controllers release];

    // a page is the width of the scroll view
    scrollView.pagingEnabled = YES;
    scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * kNumberOfPages,        scrollView.frame.size.height);
    scrollView.showsHorizontalScrollIndicator = NO;
    scrollView.showsVerticalScrollIndicator = NO;
    scrollView.scrollsToTop = NO;
    scrollView.delegate = self;

    pageControl.numberOfPages = kNumberOfPages;
    pageControl.currentPage = currentPage;

    [self loadScrollViewWithPage:0];
    [self loadScrollViewWithPage:1];
}

更新:乐器http://www.youtube.com/watch?v=u1Rd2clvMQE&feature=youtube_gdata_player

的视频录制

显示负责的来电者的屏幕截图: enter image description here

谢谢。

4 个答案:

答案 0 :(得分:2)

Apple的PageControl示例代码已有2年的历史了,您可以将其视为已弃用,因为iOS 5中有一个新的容器视图控制器可以完成所有这些操作:UIPageViewController

您应该真正开始使用UIPageViewController,然后根本不需要loadScrollViewWithPage方法。这将是更少的代码,更容易。

查看PhotoScroller示例代码。它已更新,以充分利用UIPageViewController

答案 1 :(得分:2)

如果您不想使用UIPageViewController(请阅读我的其他答案),这是给您的。

示例项目是针对恒定页数(kNumberOfPages)而设计的。 scrollview内容大小和视图控制器阵列的大小取决于页数。示例代码在awakeFromNib中设置了它,它只被调用一次。

因此,为了使这个动态化,您可以在页面数量发生变化时重新创建整个ContentController。您只需要为页数添加属性。

另一个选项是在页数改变时重置滚动视图和视图控制器数组。

我假设您已为事件定义了一个属性:

@property(nonatomic,retain) NSArray* eventsArray;

然后你可以添加这样的setter方法:

-(void)setEventsArray:(NSArray *)eventsArray
{
    if (eventsArray != _eventsArray) {
        [_eventsArray release];
        _eventsArray = [eventsArray retain];
        NSUInteger eventCount = [eventsArray count];
        //reset scrollview contentSize
        scrollView.contentSize = CGSizeMake(scrollView.frame.size.width * eventCount, scrollView.frame.size.height);

        // reset content offset to zero
        scrollView.contentOffset = CGPointZero;

        //remove all subviews
        [[scrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];

        pageControl.numberOfPages = eventCount;

        // reset viewcontroller array
        NSMutableArray *controllers = [[NSMutableArray alloc] init];
        for (unsigned i = 0; i < eventCount; i++)
        {
            [controllers addObject:[NSNull null]];
        }
        self.viewControllers = controllers;
        [controllers release];

        [self loadScrollViewWithPage:0];
        [self loadScrollViewWithPage:1];
    }
}

当用户切换到滚动视图时,您可以从表视图控制器中调用此方法。

答案 2 :(得分:1)

看起来你似乎没有实施Apple的View Controller Containment实践。这将使内存管理变得更加容易和安全。

另外,希望它可以为您节省很多未来的麻烦,已经有一个开源项目可以完成您所描述的内容(实现自动管理的一系列视图控制器的滚动视图)。

您可能需要查看它:RHHorizontalSwipe

答案 3 :(得分:1)

包含多个UIViewController视图的UIScrollView概念听起来很粗略,设计听起来不太好。

话虽如此,一个潜在的问题可能是这一行:

if ((NSNull *)countdownController == [NSNull null]) 

你最好用这样的东西:

if (!countdownController || [countdownController isKindOfClass:[NSNull class]])

另外,您应该使用[super viewWillDisappear:animated]方法拨打viewWillDisappear