我的 UIScrollView 助手类中的泄漏

Posted

技术标签:

【中文标题】我的 UIScrollView 助手类中的泄漏【英文标题】:Leaks in my UIScrollView helper class 【发布时间】:2010-04-09 09:12:27 【问题描述】:

我想发布关于如何在http://www.xprogress.com/ 上轻松创建 UIScrollView 的教程,我只想在发布任何内容之前与你们确认代码是否正常。任何帮助将不胜感激,我会将您的姓名/网站放在文章底部:)

非常感谢:)

翁德瑞

头文件:

///
///  IGUIScrollViewImage.h
///
///  IGUILibrary
///
///  Created by Ondrej Rafaj on 7.4.10.
///
///  Copyright 2010 Home. All rights reserved.
///
/// @todo enable margin and center the image to the middle of the view

/**

 <b>Examples:</b>

 <i>This is just a short example how to use this class</i>

 <pre>
 - (NSArray *)getImages 
    NSMutableArray *arr = [[[NSMutableArray alloc] init] autorelease];
    [arr addObject:[UIImage imageNamed:@"image-1.jpg"]];
    [arr addObject:[UIImage imageNamed:@"image-2.png"]];
    [arr addObject:[UIImage imageNamed:@"image-3.png"]];
    [arr addObject:[UIImage imageNamed:@"image-4.jpg"]];
    return (NSArray *)arr;
 

 - (void)viewDidLoad 
    IGUIScrollViewImage *svimage = [[IGUIScrollViewImage alloc] init];

    [svimage setSizeFromScrollView:self.scrView]; // takes size of the scroll view you've already placed on stage via Interface Builder
    // or
    //[svimage setWidth:320 andHeight:240]; // half screen

    [svimage enablePositionMemory]; // enables position (pagination) memory for this scroll view
    // or
    //[svimage enablePositionMemoryWithIdentifier:@"myIdentifier"]; if you have more instances of this scroll view in your application

    [svimage enablePageControlOnBottom];
    // or
    //[svimage enablePageControlOnTop];

    [self.myUIView addSubview:[svimage get]]; // and place it on the stage :)
    [super viewDidLoad];
 
 </pre>


 */

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>


@interface IGUIScrollViewImage : NSObject <UIScrollViewDelegate> 

    UIScrollView *scrollView;
    UIPageControl *pageControl;

    CGRect rectScrollView;
    CGRect rectPageControl;

    int scrollWidth;
    int scrollHeight;

    NSArray *contentArray;

    UIColor *bcgColor;

    BOOL pageControlEnabledTop;
    BOOL pageControlEnabledBottom;

    BOOL rememberPosition;
    NSString *positionIdentifier;



@property (nonatomic, retain) UIScrollView *scrollView;

- (int)getScrollViewWidth;

- (void)setWidth:(int)width andHeight:(int)height;

- (void)setSizeFromScrollView:(UIScrollView *)scView;

- (void)setBackGroudColor:(UIColor *)color;

- (void)setContentArray:(NSArray *)images;

- (void)enablePageControlOnTop;

- (void)enablePageControlOnBottom;

- (void)enablePositionMemory;

- (void)enablePositionMemoryWithIdentifier:(NSString *)identifier;

- (UIScrollView *)getWithPosition:(int)page;

- (UIScrollView *)getWithPositionMemoryIdentifier:(NSString *)identifier;

- (UIScrollView *)get;

@end

以及实现文件:

//
//  IGUIScrollViewImage.m
//  IGUILibrary
//
//  Created by Ondrej Rafaj on 7.4.10.
//  Copyright 2010 Home. All rights reserved.
//

#import "IGUIScrollViewImage.h"

#define kIGUIScrollViewImagePageIdentifier                      @"kIGUIScrollViewImagePageIdentifier"
#define kIGUIScrollViewImageDefaultPageIdentifier               @"Default"


@implementation IGUIScrollViewImage

@synthesize scrollView;

- (int)getScrollViewWidth 
    return ([contentArray count] * scrollWidth);


- (void)setWidth:(int)width andHeight:(int)height 
    scrollWidth = width;
    scrollHeight = height;
    if (!width || !height) rectScrollView = [[UIScreen mainScreen] applicationFrame];
    else rectScrollView = CGRectMake(0, 0, width, height);


- (void)setSizeFromScrollView:(UIScrollView *)scView 
    scrollWidth = scView.frame.size.width;
    scrollHeight = scView.frame.size.height;
    rectScrollView = CGRectMake(0, 0, scrollWidth, scrollHeight);


- (void)setContentArray:(NSArray *)images 
    contentArray = images;


- (void)setBackGroudColor:(UIColor *)color 
    bcgColor = color;


- (void)enablePageControlOnTop 
    pageControlEnabledTop = YES;


- (void)enablePageControlOnBottom 
    pageControlEnabledBottom = YES;


- (void)enablePositionMemoryWithIdentifier:(NSString *)identifier 
    rememberPosition = YES;
    if (!identifier) identifier = kIGUIScrollViewImageDefaultPageIdentifier;
    positionIdentifier = identifier;


- (void)enablePositionMemory 
    [self enablePositionMemoryWithIdentifier:nil];


- (UIScrollView *)getWithPosition:(int)page 
    if (!contentArray) 
        contentArray = [[[NSArray alloc] init] autorelease];
    
    if (page > [contentArray count]) page = 0;

    if (!scrollWidth || !scrollHeight) 
        rectScrollView = [[UIScreen mainScreen] applicationFrame];
        scrollWidth = rectScrollView.size.width;
        scrollHeight = rectScrollView.size.height;
    
    rectScrollView = CGRectMake(0, 0, scrollWidth, scrollHeight);

    self.scrollView = [[UIScrollView alloc] initWithFrame:rectScrollView];
    self.scrollView.contentSize = CGSizeMake([self getScrollViewWidth], scrollHeight);
    if (!bcgColor) bcgColor = [UIColor blackColor];
    self.scrollView.backgroundColor = bcgColor;
    self.scrollView.alwaysBounceHorizontal = YES;
    self.scrollView.contentOffset = CGPointMake(page * scrollWidth, 0);
    self.scrollView.pagingEnabled = YES;

    UIImageView *imageView;
    UIView *main = [[[UIView alloc] initWithFrame:rectScrollView] autorelease];
    int i = 0;
    for (UIImage *img in contentArray) 
        imageView = [[UIImageView alloc] initWithImage:img];
        imageView.contentMode = UIViewContentModeScaleAspectFit;
        imageView.autoresizingMask = ( UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
        imageView.backgroundColor = [UIColor blackColor];
        float ratio = img.size.width/rectScrollView.size.width;
        CGRect imageFrame = CGRectMake(i, 0, rectScrollView.size.width, (img.size.height / ratio));
        imageView.frame = imageFrame;
        [self.scrollView addSubview:imageView];
        i += scrollWidth;
    
    [imageView release];
    [main addSubview:scrollView];
    if (pageControlEnabledTop) 
        rectPageControl = CGRectMake(0, 5, scrollWidth, 15);
    
    else if (pageControlEnabledBottom) 
        rectPageControl = CGRectMake(0, (scrollHeight - 25), scrollWidth, 15);
    
    if (pageControlEnabledTop || pageControlEnabledBottom) 
        pageControl = [[[UIPageControl alloc] initWithFrame:rectPageControl] autorelease];
        pageControl.numberOfPages = [contentArray count];
        pageControl.currentPage = page;
        [main addSubview:pageControl];
    
    if (pageControlEnabledTop || pageControlEnabledBottom || rememberPosition) self.scrollView.delegate = self;
    //if (margin) [margin release];
    return (UIScrollView *)main;


- (UIScrollView *)get 
    return [self getWithPosition:0];


- (UIScrollView *)getWithPositionMemoryIdentifier:(NSString *)identifier 
    [self enablePositionMemoryWithIdentifier:identifier];
    return [self getWithPosition:[[[NSUserDefaults alloc] objectForKey:[NSString stringWithFormat:@"%@%@", kIGUIScrollViewImagePageIdentifier, positionIdentifier]] intValue]];


- (void)scrollViewDidEndDecelerating:(UIScrollView *)sv 
    int page = sv.contentOffset.x / sv.frame.size.width;
    pageControl.currentPage = page;
    if (rememberPosition) 
        [[NSUserDefaults alloc] setObject:[NSString stringWithFormat:@"%d", page] forKey:[NSString stringWithFormat:@"%@%@", kIGUIScrollViewImagePageIdentifier, positionIdentifier]];
    


- (void)dealloc 
    [scrollView release];
    [super dealloc];



@end

【问题讨论】:

【参考方案1】:

快速浏览一下。您在中多次分配 UIImageView -(UIScrollView*)getWithPosition:(int)page 并且只发布一次:

for (UIImage *img in contentArray) 
    imageView = [[UIImageView alloc] initWithImage:img];
    // ...

[imageView release];

【讨论】:

以上是关于我的 UIScrollView 助手类中的泄漏的主要内容,如果未能解决你的问题,请参考以下文章

Crypto++ RSAES 类中的内存泄漏

字符串类中的字符串(const char *)构造函数内存泄漏

官方 AngularJS UI Bootstrap $modal 示例中的内存泄漏?

如何避免内部类中的内存泄漏

Interface Builder中的UIScrollView不滚动

UIScrollVIew 中的 UIView 不更新视图