iPhone - SBJsonParser的另一个Objective-C内存泄漏

时间:2011-04-11 18:09:24

标签: iphone objective-c json memory-leaks asihttprequest

我是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

这里有仪器截图:

Instruments leaks 1

Instruments leaks 2

提前致谢!

2 个答案:

答案 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)

出色的职位发布代码,以及使用工具的高五。我经常惊讶于有多少开发人员不使用它。

我知道你可能已经读过这篇文章,但请重新阅读;

http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/Learning_Objective-C_A_Primer/_index.html%23//apple_ref/doc/uid/TP40007594

像这样的代码;

self.model.myLists = [[NSMutableArray alloc] init];
[self.model.myLists addObject:userData];
[self.model.myLists retain];

表明你还没有掌握封装的概念。

model负责该列表而非外部对象非常重要。在模型类中添加代码以在init方法中创建该列表,然后添加可以调用的方法,以便将项添加到该列表中。

调用alloc表示您在此范围内有一个保留,然后再次调用retain表示您有两个。我确定还有其他类似的问题。

要了解内存管理规则,请阅读此内容;

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html%23//apple_ref/doc/uid/20000994-BAJHFBGH

上面提到的建议是黄金的,除非你明白为什么要使用它,否则不要使用asign

http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocProperties.html%23//apple_ref/doc/uid/TP30001163-CH17-SW1

详细介绍了各种选项的含义。