2012-07-21 32 views
2

我正在研究一個非常簡單和直接的應用程序,它使用幾頁滾動視圖。我有一個ViewDidLoad中的圖像數組,然後是一個可變數組,顯示當前頁面加號和減號1.有一個清除頁面方法,應該從超級視圖中刪除多餘的圖像。在具有大量圖像的實際設備上運行此應用程序時,滾動瀏覽大約50張圖像後出現內存警告,然後應用程序崩潰。我通過儀器運行它,發現每次刷卡都會大大增加內存。在創建數組時,我使用了imageNamed以及imageWithContentsOfFile,兩種方法都給出了接近相同的結果。我意識到這裏有多個滾動視圖問題,但不知何故,我似乎無法通過這一個。沮喪地說至少。我希望有人可以用一雙新的眼睛來看待這個問題,並對我的問題進行闡述。首先十分感謝。UIScrollView內存分配和發佈

編輯:忘了提及ARC使用。是的,我使用ARC。

代碼:.h文件中

#import <UIKit/UIKit.h> 

@interface FirstViewController : UIViewController <UIScrollViewDelegate> 

@property (nonatomic, strong) IBOutlet UIScrollView *scrollView; 
@property (nonatomic, strong) IBOutlet UIPageControl *pageControl; 

@end 

與.m文件

#import "FirstViewController.h" 

@interface FirstViewController() 

@property (nonatomic, strong) NSArray *pageImages; 
@property (nonatomic, strong) NSMutableArray *pageViews; 

- (void)loadVisiblePages; 
- (void)loadPage:(NSInteger)page; 
- (void)purgePage:(NSInteger)page; 
@end 

@implementation FirstViewController 


@synthesize scrollView = _scrollView; 
@synthesize pageControl = _pageControl; 

@synthesize pageImages = _pageImages; 
@synthesize pageViews = _pageViews; 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{ 
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 
    if (self) { 
     // Custom initialization 
    } 
    return self; 
} 

- (void)didReceiveMemoryWarning 
{ 
    // Releases the view if it doesn't have a superview. 
    [super didReceiveMemoryWarning]; 

    // Release any cached data, images, etc that aren't in use. 
} 

- (void)loadVisiblePages { 
    // First, determine which page is currently visible 
    CGFloat pageWidth = self.scrollView.frame.size.width; 
    NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) /(pageWidth * 2.0f)); 

// Update the page control 
self.pageControl.currentPage = page; 

// Work out which pages you want to load 
NSInteger firstPage = page - 1; 
NSInteger lastPage = page + 1; 

// Purge anything before the first page 
for (NSInteger i=0; i<firstPage; i++) { 
    [self purgePage:i]; 
} 

// Load pages in our range 
for (NSInteger i=firstPage; i<=lastPage; i++) { 
    [self loadPage:i]; 
} 

// Purge anything after the last page 
for (NSInteger i=lastPage+1; i<self.pageImages.count; i++) { 
    [self purgePage:i]; 
} 

} 

- (void)purgePage:(NSInteger)page { 
    if (page < 0 || page >= self.pageImages.count) { 
    // If it's outside the range of what you have to display, then do nothing 
    return; 
    } 

    // Remove a page from the scroll view and reset the container array 
    UIView *pageView = [self.pageViews objectAtIndex:page]; 
    if ((NSNull*)pageView != [NSNull null]) { 
     [pageView removeFromSuperview]; 
     [self.pageViews replaceObjectAtIndex:page withObject:[NSNull null]]; 


    } 

} 


- (void)loadPage:(NSInteger)page { 
    if (page < 0 || page >= self.pageImages.count) { 
     // If it's outside the range of what you have to display, then do nothing 
     return; 
    } 

    // 1 
    UIView *pageView = [self.pageViews objectAtIndex:page]; 
    if ((NSNull*)pageView == [NSNull null]) { 
     // 2 
     CGRect frame = self.scrollView.bounds; 
     frame.origin.x = frame.size.width * page; 
     frame.origin.y = 0.0f; 

     // 3 
     UIImageView *newPageView = [[UIImageView alloc] initWithImage:[self.pageImages objectAtIndex:page]]; 
     newPageView.contentMode = UIViewContentModeScaleAspectFit; 
     newPageView.frame = frame; 
     [self.scrollView addSubview:newPageView]; 
     // 4 
     [self.pageViews replaceObjectAtIndex:page withObject:newPageView]; 

    } 
} 

- (void)scrollViewDidScroll:(UIScrollView *)scrollView { 
    // Load the pages that are now on screen 
    [self loadVisiblePages]; 
} 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    // 1 
    self.pageImages = [NSArray arrayWithObjects: 
         [UIImage imageNamed:@"BBD1.jpg"], 
         [UIImage imageNamed:@"BBD2.jpg"], 
         [UIImage imageNamed:@"BBD3.jpg"], 
         [UIImage imageNamed:@"BBD4.jpg"], 
         [UIImage imageNamed:@"BBD5.jpg"], 
         [UIImage imageNamed:@"BBD6.jpg"], 
         [UIImage imageNamed:@"BBD7.jpg"], 
        ..... 
         [UIImage imageNamed:@"BBD292.jpg"], 
         [UIImage imageNamed:@"BBD293.jpg"], 
         [UIImage imageNamed:@"BBD294.jpg"], 
         [UIImage imageNamed:@"BBD295.jpg"], 
         [UIImage imageNamed:@"BBD296.jpg"], 
         [UIImage imageNamed:@"BBD297.jpg"], 
         [UIImage imageNamed:@"BBD298.jpg"], 
         [UIImage imageNamed:@"BBD299.jpg"], 
         [UIImage imageNamed:@"BBD300.jpg"],      


         nil]; 

    NSInteger pageCount = self.pageImages.count; 

    // 2 
    self.pageControl.currentPage = 0; 
    self.pageControl.numberOfPages = pageCount; 

    // 3 
    self.pageViews = [[NSMutableArray alloc] init]; 
    for (NSInteger i = 0; i < pageCount; ++i) { 
     [self.pageViews addObject:[NSNull null]]; 
    } 
} 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 

    // 4 
    CGSize pagesScrollViewSize = self.scrollView.frame.size; 
    self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width *  self.pageImages.count, pagesScrollViewSize.height); 

    // 5 
    [self loadVisiblePages]; 
} 

- (void)viewDidUnload 
{ 
    [super viewDidUnload]; 
    // Release any retained subviews of the main view. 
} 

- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation 
{ 
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) { 
     return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 
    } else { 
     return YES; 
    } 
} 

@end 

我真的很感謝您抽出時間來看看這個,希望有一個人在那裏誰可以點我在正確的方向。

謝謝!

+0

在'// 3'中,您不會釋放已創建的圖像視圖。 – 2012-07-21 18:00:24

回答

0

你不會說如果你使用的是ARC或者沒有,但是沒有ARC的話在內存管理上會有明顯的問題。在loadPage:的註釋「// 3」處,您創建newPageView,保留計數爲1,然後將其作爲子視圖self.scrollView和數組self.pageViews添加爲子視圖。因此總體保留數爲+3。在purgePage:中,您將其從self.scrollViewself.pageViews中刪除,但仍保留整體保留數+1。因此,每個頁面的UIImageView已被遺忘但未被釋放。

UIImageView *newPageView = [[[UIImageView alloc] initWithImage:[self.pageImages objectAtIndex:page]] autorelease]; 
+0

我的確擁有ARC的設置。 – 2012-07-21 18:08:07

+0

在這種情況下,我一眼就看不出有什麼不對。可能有時間抽出內存跟蹤工具,如泄漏和使用Instruments應用程序使用堆分析分析,如[bbum的文章]中所述(http://www.friday.com/bbum/2010/10/17/when-是-A-泄漏值爲非泄漏使用-heapshot分析找到的-不期望的存儲器生長/)。 – 2012-07-21 21:49:19

3

加載實際圖像放入數組招致不是存儲只是名稱的更大的開銷:

您可以通過在項目中使用ARC或修改在其中創建newPageView是替代線路解決這個問題陣列和裝載等

UIImage *image = [[UIImage alloc] initWithContentsOfFile:[self.pageImages objectAtIndex:page]]; 
UIImageView *newPageView = [[UIImageView alloc] initWithImage:image]; 
[image release]; 

圖像此時在,只有newPageView將存儲器保持的圖像的參考,並且當移除newPageView從它的上海華,在存儲器中的圖像將被釋放。