我是iPhone开发和Stack Overflow问题的新手。我从1月份开始做我的第一个应用程序。
我的应用有与SBJsonParser相关的内存泄漏。经过一些谷歌搜索后,我在stackoverflow上找到了另一个post。感谢Konrad77在answer上发布的功能,我改变了我的应用程序的一些行。但我仍然在内存泄漏。我将不胜感激。我正在使用AsiHttpRequest 1.8和JSONframework 3.0beta1。
仪器告诉我,泄漏发生在MyLists.m的以下行中,为99.2%:
resultObject = [self.model JSONObjectForRequest:request];
另外0.8%转到以下MyLists.m行:
[self.model.myLists addObject:userData];
以前的两行都在listaGetRequestOnResult函数中。这里有相关的所有代码:
-MyLists.h:
#import <UIKit/UIKit.h>
#import "Model.h"
#import "ASIFormDataRequest.h"
@interface MyLists : UITableViewController {
Model *model;
NSObject *resultObject;
}
@property (assign) Model *model;
@property (nonatomic,assign) NSObject *resultObject;
@end
-MyLists.m:
#import "MyLists.h"
#import "ASIFormDataRequest.h"
@implementation MyLists
@synthesize model;
@synthesize resultObject;
-(void)loadListData {
[self showWaitPopup:CARGANDO];
//Remote listaGet operation
NSURL *url = [NSURL URLWithString:self.model.operationsURL];
ASIFormDataRequest *postRequest = [ASIFormDataRequest requestWithURL:url];
[postRequest setPostValue:@"listaGet" forKey:@"action"];
[postRequest setPostValue:@"JSON" forKey:@"format"];
[postRequest setDelegate:self];
[postRequest setDidFinishSelector:@selector(listaGetRequestOnResult:)];
[postRequest setDidFailSelector:@selector(listaGetRequestOnFault:)];
[postRequest startAsynchronous];
}
- (void)listaGetRequestOnResult:(ASIFormDataRequest *)request {
[self hideWaitPopup:CARGANDO];
resultObject = [self.model JSONObjectForRequest:request];
NSDictionary *data = (NSDictionary *)resultObject;
NSNumber *errorCode = [data valueForKey:@"errorCode"];
if ([errorCode intValue] == 0) {
//Remote operation did end successfully
NSMutableArray *userData = [data valueForKey:@"data"];
//Set list into model For now, only one component for the table
[self reinitializeTableList:FALSE];
self.model.myLists = [[NSMutableArray alloc] init];
[self.model.myLists addObject:userData];
[self.model.myLists retain];
} else {
//Remote operation did end succesfully but returned and error
[model reportError:[data valueForKey:@"errorText"] withTitle:@"Error"];
[self reinitializeTableList:FALSE];
}
[self.tableView reloadData];
}
- (void)listaGetRequestOnFault:(ASIFormDataRequest *)request {
[self hideWaitPopup:CARGANDO];
NSError *error = [request error];
[model reportError:[error localizedDescription] withTitle:@"Error de conexión"];
[self reinitializeTableList:TRUE];
}
-(void)reinitializeTableList:(BOOL)reloadTableData {
if (self.model.myLists) {
[self.model.myLists release];
}
self.model.myLists = nil;
if (reloadTableData) {
[self.tableView reloadData];
}
}
- (void)viewDidLoad {
self.model = [Model getModel];
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[self loadListData];
[super viewWillAppear:animated];
}
- (void)dealloc {
model = nil;
resultObject = nil;
[super dealloc];
}
@end
-Model.h:
#import <Foundation/Foundation.h>
#import "ASIHTTPRequest.h"
@interface Model : NSObject {
NSString *operationsURL;
NSString *imagesBaseURL;
NSMutableArray *myLists;
}
@property (retain) NSString *operationsURL;
@property (retain) NSString *imagesBaseURL;
@property (retain) NSMutableArray *myLists;
+ (Model*) getModel;
//+ (id) allocWithZone:(NSZone *) zone;
+ (void) initModel;
- (void)reportError:(NSString*)mensaje withTitle:(NSString*)withTitle;
- (NSObject*)JSONObjectForRequest:(ASIFormDataRequest *)request;
@end
-Model.m:
#import "Model.h"
#import "ASIHTTPRequest.h"
#import "JSON.h"
@implementation Model
static Model *uniqueInstance = nil;
@synthesize operationsURL;
@synthesize imagesBaseURL;
@synthesize myLists;
+ (Model*) getModel {
@synchronized(self) {
if (uniqueInstance == nil) {
uniqueInstance = [[Model alloc] init];
[self initModel];
}
}
return uniqueInstance;
}
/*+ (id) allocWithZone:(NSZone *) zone {
@synchronized(self) {
if (uniqueInstance == nil) {
uniqueInstance = [super allocWithZone:zone];
return uniqueInstance;
}
}
return nil;
}*/
+ (void) initModel {
//URL
uniqueInstance.operationsURL=[NSString stringWithFormat:@"SOME_URL"];
uniqueInstance.imagesBaseURL=[NSString stringWithFormat:@"SOME_URL"];
}
-(void)reportError:(NSString*)mensaje withTitle:(NSString*)withTitle {
UIAlertView *alertDialog;
alertDialog = [[UIAlertView alloc] initWithTitle:withTitle
message:[NSString stringWithFormat:@"%@",mensaje]
delegate: nil
cancelButtonTitle: @"Aceptar"
otherButtonTitles:nil];
[alertDialog show];
[alertDialog release];
}
- (NSObject*)JSONObjectForRequest:(ASIFormDataRequest *)request {
SBJsonParser *jsonParser = [SBJsonParser new];
NSObject *object=[jsonParser objectWithString:[request responseString] error:nil];
if (object == nil) {
[self reportError:[jsonParser error] withTitle:@"Error librería JSON"];
}
[jsonParser release], jsonParser = nil;
return object;
}
- (void)dealloc {
[operationsURL release];
[imagesBaseURL release];
[myLists release];
[super dealloc];
}
@end
这里有仪器截图:
提前致谢!
答案 0 :(得分:2)
你的泄漏(它实际上有两个额外的保留):
self.model.myLists = [[NSMutableArray alloc] init];
[self.model.myLists addObject:userData];
[self.model.myLists retain];
你可能想要这样的东西:
self.model.myLists = [NSMutableArray arrayWithObject:userData];
我也不会像你一样使用assign
属性。
答案 1 :(得分:1)
出色的职位发布代码,以及使用工具的高五。我经常惊讶于有多少开发人员不使用它。
我知道你可能已经读过这篇文章,但请重新阅读;
像这样的代码;
self.model.myLists = [[NSMutableArray alloc] init];
[self.model.myLists addObject:userData];
[self.model.myLists retain];
表明你还没有掌握封装的概念。
model
负责该列表而非外部对象非常重要。在模型类中添加代码以在init
方法中创建该列表,然后添加可以调用的方法,以便将项添加到该列表中。
调用alloc
表示您在此范围内有一个保留,然后再次调用retain
表示您有两个。我确定还有其他类似的问题。
要了解内存管理规则,请阅读此内容;
上面提到的建议是黄金的,除非你明白为什么要使用它,否则不要使用asign
。
详细介绍了各种选项的含义。