可能优化卸载在 UIScrollView 和 PageControl 中不再可见的视图控制器
我的页面控制代码与苹果示例相同。这里我有一个包含 ImageView 的子视图(controller.view)。现在问题出在内存管理上。一切正常。但是当我滚动 5-10 页时。 RAM 已满。 我尝试释放视图+控制器,但没有找到任何合适的工作位置/方式。我想发布当前不可见的视图。 (当前、上一个和下一个视图除外)
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
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 = 0;
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= kNumberOfPages) return;
PageControlExampleViewControl *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[PageControlExampleViewControl alloc] initWithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (pageControlUsed) {
return;
}
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
int page = pageControl.currentPage;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
I have this page control code same from the apple sample. Here i have a subview (controller.view) which contains a ImageView. Now problem is with memory management. All works fine. But when i scroll 5-10 pages. RAM gets filled.
I tried to release the view+controller but did not find any proper place/way that work. I want to release the views which are not currently visible. (except current,previous & next view)
- (void)applicationDidFinishLaunching:(UIApplication *)application {
NSMutableArray *controllers = [[NSMutableArray alloc] init];
for (unsigned i = 0; i < kNumberOfPages; i++) {
[controllers addObject:[NSNull null]];
}
self.viewControllers = controllers;
[controllers release];
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 = 0;
[self loadScrollViewWithPage:0];
[self loadScrollViewWithPage:1];
}
- (void)loadScrollViewWithPage:(int)page {
if (page < 0) return;
if (page >= kNumberOfPages) return;
PageControlExampleViewControl *controller = [viewControllers objectAtIndex:page];
if ((NSNull *)controller == [NSNull null]) {
controller = [[PageControlExampleViewControl alloc] initWithPageNumber:page];
[viewControllers replaceObjectAtIndex:page withObject:controller];
[controller release];
}
if (nil == controller.view.superview) {
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
controller.view.frame = frame;
[scrollView addSubview:controller.view];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)sender {
if (pageControlUsed) {
return;
}
CGFloat pageWidth = scrollView.frame.size.width;
int page = floor((scrollView.contentOffset.x - pageWidth / 2) / pageWidth) + 1;
pageControl.currentPage = page;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
pageControlUsed = NO;
}
- (IBAction)changePage:(id)sender {
int page = pageControl.currentPage;
[self loadScrollViewWithPage:page - 1];
[self loadScrollViewWithPage:page];
[self loadScrollViewWithPage:page + 1];
CGRect frame = scrollView.frame;
frame.origin.x = frame.size.width * page;
frame.origin.y = 0;
[scrollView scrollRectToVisible:frame animated:YES];
pageControlUsed = YES;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我尝试了几个小时 Deepmist 的代码。它完成了这项工作,但我收到了内存警告,并且我的应用程序每滚动 25-30 页就会崩溃(我在页面中使用大图像)。在 Instruments 中,我注意到内存的使用量非常大:即使一次又一次地从 superview 中删除不必要的视图,并将相关的 viewController 替换为 NSNulls,Instruments 也显示,每滚动一页,实际内存就会增加 4-5MB!
在网上搜索了一下,发现这是一个常见问题。如果您也遇到此问题,您应该尝试以下检查:
1) 在每个视图中,确保使用 imageWithContentsOfFile 而不是 imageNamed。正如记录的 imageNamed 缓存图像并增加内存大小。
2) 在 Deepmist 代码中,之后:
您还必须将视图设置为 nil:
这个技巧解决了内存消耗问题,现在对于加载的唯一三个视图(当前、当前-1 和当前+1)来说内存消耗是稳定的,以避免在页面滚动)。
希望这有帮助!
I tried for several hours the code of Deepmist. It did the job but I received memory warnings and my app crashed every 25-30 pages scrolled (I am using big images in the pages). In Instruments I noticed a very large use of memory: even if the unnecessary views were removed time by time from superview and the relative viewControllers were replaced with NSNulls, Instruments showed that real memory increased on every pagescroll of 4-5MB!
Searching on the web I found that this is a common problem. If you also have this problem, you should try the following checks:
1) in each view, be sure to use imageWithContentsOfFile instead of imageNamed. As documented imageNamed cache images and increase memory size.
2) in the Deepmist code, after:
you also have to set to nil the view:
This trick solved the memory consumption which now is stable for the only three views loaded (current, current-1 and current+1 to avoid flashing in the pagescroll).
Hope this helps!
我没有测试这个,但我想你可以编写一个与加载相反的方法,如下所示:
然后向 didScroll 方法添加一些代码,如下所示:
I didn't test this but I imagine you could write a method that does the opposite of loading like so:
Then add some code to your didScroll method like so:
在 loadScrollViewWithPage 方法中,在 if (nil ==controller.view.superview) 之前,循环遍历所有视图并删除除当前 -1、当前和当前 + 1 之外的所有视图,但前提是使用当前索引视图调用该方法。另外,不要忘记将 viewControllers 数组中的视图控制器替换为 NSNulls。
in loadScrollViewWithPage method, just before if (nil == controller.view.superview), cycle trough all views and remove them all except current -1, current and current + 1 but only if method was called with current index view. Also, don't forget to replace those view controllers in viewControllers array with NSNulls.
尝试 this VSScrollview ,它重用其视图,就像 UITableview 重用其单元格一样。
try this VSScrollview , it reuses its views like UITableview reuses its cell.