0

我将 UINavigationController 和 UITableview 子类化,出于某种原因,我的视图正在泄漏内存,尽管我已经实现了所有正确的方法和释放调用。当我使用本机类而不是子类时,一切正常,没有泄漏。

编辑:

这是我的超类标题:

//
//  MBAbstractViewController.h
//  GabbaiHD
//
//  Created by Moshe Berman on 11/24/10.
//  Copyright 2010 MosheBerman.com. All rights reserved.
//

#import <UIKit/UIKit.h>


@interface MBAbstractViewController : UIViewController {
    IBOutlet UIImageView *backgroundImageView;
    NSString *announcementText;
}

@property (nonatomic, retain) NSString *type;
@property (nonatomic, retain) NSDictionary *options;
@property (nonatomic, retain) NSString *announcementText;

-(void) setAnnouncementText:(NSString *)text;

@end

超类实现:

//
//  MBAbstractViewController.m
//  GabbaiHD
//
//  Created by Moshe Berman on 11/24/10.
//  Copyright 2010 MosheBerman.com. All rights reserved.
//

#import "MBAbstractViewController.h"


@implementation MBAbstractViewController

@synthesize type, options, announcementText;

 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization.
    }
    return self;
}
*/

/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/

// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];
    UIColor *clearColor = [[UIColor alloc] colorWithAlphaComponent:0.0];
    [self.view setBackgroundColor: clearColor];
    [clearColor release];
}


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    if(interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||  interfaceOrientation == UIInterfaceOrientationLandscapeRight){
        return YES;
    }else{
        return NO;
    }
}

- (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)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;

}


- (void)dealloc {
    [announcementText release];
    [options release];
    [type release];
    [super dealloc];
}


@end

这是我的子类标题:

//
//  MBAnnouncementViewController.h
//  GabbaiHD
//
//  Created by Moshe Berman on 11/24/10.
//  Copyright 2010 MosheBerman.com. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "MBAbstractViewController.h"

@interface MBAnnouncementViewController : MBAbstractViewController {
    IBOutlet UILabel *announcement;
}

- (void) setAnnouncementText:(NSString *)text withSize:(CGFloat)size;

@end

和子类实现:

        //
//  MBAnnouncementViewController.m
//  GabbaiHD
//
//  Created by Moshe Berman on 11/24/10.
//  Copyright 2010 MosheBerman.com. All rights reserved.
//

#import "MBAnnouncementViewController.h"
#import "Constants.h"[

@implementation MBAnnouncementViewController

 // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization.
    }
    return self;
}
*/


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
    [super viewDidLoad];

    [announcement setText:announcementText]; 

    UIImage *slideImage = [[UIImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:[[NSString stringWithFormat:@"%@_slide", kTheme]description] ofType:@"png"]];  
    [backgroundImageView setImage:slideImage];
    [slideImage release];   


}



- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    // Overriden to allow any orientation.
    return YES;
}


- (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) setAnnouncementText:(NSString *)text withSize:(CGFloat)size{
    UIFont *font = [[UIFont alloc] fontWithSize:size];
    [announcement setFont:font];
    [font release];
    [announcement setText:text];

}

- (void)viewDidUnload {
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [announcementText release];
    [super dealloc];
}


@end

什么可能导致子类中的内存泄漏?我错过了什么吗?(这里有更多相关代码。)

4

4 回答 4

2

在您的子类中,我注意到您有一个似乎没有出现在您的超类中的“公告”变量。

我假设您的超类具有以下变量:

type
options
announcementText

虽然您的子类有一个附加变量:

announcement

在子类的 dealloc 中,您 release announcementText(也在超类中发布), not announcement,这可能是您泄漏的原因。

于 2010-11-29T22:10:21.153 回答
1

你不应该UIColor以这种方式分配:

[[UIColor alloc] colorWithAlphaComponent:0.0];

您在没有初始化的情况下分配了实例,然后您调用了工厂方法并丢失了对您分配的实例的引用。

您需要在调用之前调用其中一个初始化程序colorWithAlphaComponent:。我不确定如果你不这样做会是什么行为。为什么不只是[UIColor clearColor];

你也犯了同样的错误UIFont

UIFont *font = [[UIFont alloc] fontWithSize:size];

你不应该这样做。您链接到的唯一方法+alloc应该是初始化程序(它总是返回分配的任何内容)。您在这里泄漏,并且我敢说还有一些奇怪的意外行为。

此外,正如 David Liu 所说,您似乎过度释放announcementText和释放不足announcement,这将导致崩溃和泄漏,具体取决于您的幸运程度。

编辑 | 根据显示头文件的更新,还有其他问题(与泄漏无关)。

@property (nonatomic, retain) NSString *announcementText;

你永远不应该保留NSString*; 相反,你应该copy这样做。

@property (nonatomic, copy) NSString *announcementText;

这是因为NSString*实际上可能是一个可变字符串并且稍后会更改。retain但是,如果您特别想要这个,您可以使用。

-setAnnouncementText:当您拥有@property announcementText.

在您的子类中实际上对ivarsetAnnouncementText:withSize:没有任何作用,我猜这很令人困惑。announcementText您需要释放announcementivar 并解决问题UIColorUIFont使用不正确(正在泄漏)。

于 2010-11-29T22:35:51.877 回答
0

在您的第二堂课中,“公告”代表什么?它是一个 IBOutlet(我没有看到它的合成)吗?如果它是一个属性或 IBOutlet,你需要确保在你的 dealloc 中释放它。

于 2010-11-29T21:55:53.790 回答
0

根据UIViewController 文档

...如果您的视图控制器包含插座(包含 IBOutlet 关键字的属性或原始变量),您应该使用 viewDidUnload 方法放弃这些插座或您不再需要的任何其他视图相关数据的所有权。

尝试发布announcementviewDidUnload因为它是一个 IBOutlet,Interface Builder 保留它。

- (void)viewDidUnload {
    [super viewDidUnload];
    [announcement release];
    announcement = nil;
}
于 2010-11-29T21:40:39.723 回答