在滚动视图中释放多个视图控制器的内存
我有一个应用程序在滚动视图中加载了许多视图控制器取决于用户在桌面视图中的对象的数量。 所以当我在tableview和scroll view之间切换时,滚动视图中视图控制器的数量根据用户在tableview中有多less个对象而改变。
我使用Apple的PageControl示例代码中的代码,在经过一些修改之后,使用其中的许多视图控制器来构build滚动视图。
- (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)的数量也会不断增加。
我在viewWill中显示了如此多的东西,
- (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]; } }
但它没有工作。 这里是一个logging应用程序如何工作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]; }
更新:仪器的video录像http://www.youtube.com/watch?v=u1Rd2clvMQE&feature=youtube_gdata_player
并显示负责人的屏幕截图:
谢谢。
这是给你,如果你不想使用UIPageViewController
(阅读我的其他答案)。
示例项目devise为一个固定数量的页面( kNumberOfPages
)。 scrollview的内容大小和视图控制器数组的大小取决于页面的数量。 示例代码将其设置在awakeFromNib中,只调用一次。
所以为了使这个dynamic,你可以重新创build整个ContentController的页面数量的变化。 你只需要添加一个属性的页数。
另一个选项是当页面数量改变时重置scrollview和view controller数组。
我假设你已经为事件定义了一个属性:
@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]; } }
当用户切换到滚动视图时,您可以从表视图控制器调用此方法。
苹果的PageControl示例代码是2岁,你可以认为它已被弃用,因为在iOS 5中有一个新的容器视图控制器完成这一切: UIPageViewController
。
你应该真的开始使用UIPageViewController
,那么你根本就不需要loadScrollViewWithPage方法。 这将是更less的代码,更容易。
看看PhotoScroller示例代码。 它已被更新以充分利用UIPageViewController
。
看起来你并没有实施苹果的View Controller Containment实践 。 这将使内存pipe理变得更容易和更安全。
另外,希望它可以为您节省大量的未来的头痛,已经有一个开源项目,做你所描述的(实现一个自治的滚动视图的一个arbritary数量的视图控制器)。
你可能想看看它: RHHorizontalSwipe 。
包含多个UIViewController视图的UIScrollView的概念听起来似乎简单,devise听起来不太好。
这就是说,一个潜在的问题可能是这一行:
if ((NSNull *)countdownController == [NSNull null])
你会更好,像这样的东西:
if (!countdownController || [countdownController isKindOfClass:[NSNull class]])
另外,你应该在你的viewWillDisappear
方法中调用[super viewWillDisappear:animated]
。