【问题标题】:Need to call retain for a property with retain flag specified需要为指定了保留标志的属性调用保留
【发布时间】:2011-09-13 08:39:41
【问题描述】:

我是 Objective-C 的新手,作为大多数新手,我对引用管理有疑问。

我编写了一个使用 NSURLConnection 下载数据的类。该代码类似于 Apple 在http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html 中的示例。唯一的区别是 receivedData 变量被声明为“@property (nonatomic,retain) NSMutableData *receivedData;”在 .m 文件中,我有“@synthesize receivedData = _receivedData;”。

我有开始下载数据的connectionStart函数。在这个函数中我有这个代码:

if (theConnection) {
    // Create the NSMutableData to hold the received data.
    // receivedData is an instance variable declared elsewhere.
    self.receivedData = [NSMutableData data];
} else {
    // Inform the user that the connection failed.
}

程序崩溃并显示此消息:

2011-06-12 12:47:22.298 WebGallery[1212:207] *** -[NSConcreteMutableData release]: message sent to deallocated instance 0x118a6fe0

如果我将 receivedData 分配更改为此代码:

self.receivedData = [[NSMutableData data] retain];

然后程序正常运行,没有检测到内存泄漏。

如您所见,我需要在 NSMutableData 上调用 retain 并且我正在使用属性,它被声明为“retain”。

为什么会这样?

编辑:.m 文件的全部内容:

#import "GalleryData.h"
#import "XmlParser.h"

@implementation GalleryData

@synthesize receivedData = _receivedData;
@synthesize imagesData = _imagesData;
@synthesize delegate = _delegate;
@synthesize currentObjectType = _currentObjectType;
@synthesize currentObjectIndex = _currentObjectIndex;

- (id) init
{
    [super init];
    _imagesData = [[NSMutableArray alloc] init];    
    return self;
}


- (void) dealloc
{
     [_imagesData release];
    _imagesData = nil;
    [super dealloc];
}

- (void) connectionStart:(NSURL *)theURL
{
    NSURLRequest *theRequest = [NSURLRequest requestWithURL:theURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];


    NSURLConnection *theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    if (theConnection) {
        // Create the NSMutableData to hold the received data.
        // receivedData is an instance variable declared elsewhere.
        //ASK: Kodėl čia reikia daryti retain jei @property jau nustatyta retain?
        self.receivedData = [[NSMutableData data] retain];
    } else {
        // Inform the user that the connection failed.
    }

}

- (void) startLoading
{
    NSLog(@"Loading started");

    self.currentObjectIndex = 0;
    self.currentObjectType = ObjectTypeXML;
    [self connectionStart:[NSURL URLWithString:@"http://www.aleksandr.lt/gallery/data.xml"]];

}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [self.receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [self.receivedData appendData:data];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [connection release];
    [self.receivedData release];

    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [connection release];

    if (self.currentObjectType == ObjectTypeXML) {
        NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:self.receivedData];        
        XmlParser *parser = [[XmlParser alloc] initXmlParser:self.imagesData];

        [nsXmlParser setDelegate:parser];
        [nsXmlParser parse];        
        [nsXmlParser release];
        [parser release];

        [self.receivedData release];
        self.receivedData = nil;

        if ([self.imagesData count]) {
            self.currentObjectIndex = 0;
            self.currentObjectType = ObjectTypeThumbImage;
            ImageData *firstImage = [self.imagesData objectAtIndex:0];
            NSURL *theURL = [NSURL URLWithString:firstImage.thumbImageURL];
            [self connectionStart:theURL];
        } else {
            [self.delegate loadingFinished];
            return;
        }
    } else if (self.currentObjectType == ObjectTypeThumbImage) {
        ImageData *currentImage;
        currentImage = [self.imagesData objectAtIndex:self.currentObjectIndex];

        UIImage *thumbImage = [[UIImage alloc] initWithData:self.receivedData];

        if (thumbImage == nil) {
            NSLog(@"image was not created");
        }

        [currentImage setThumbImageScaled:thumbImage];

        [thumbImage release];
        [self.receivedData release];
        self.receivedData = nil;

        if (self.currentObjectIndex == ([self.imagesData count] - 1)) {
            [self.delegate loadingFinished];
            return;
        }

        self.currentObjectIndex++;

        currentImage = [self.imagesData objectAtIndex:self.currentObjectIndex];
        NSLog(@"'%@'", currentImage.thumbImageURL);
        NSURL *theURL = [NSURL URLWithString:currentImage.thumbImageURL];
        [self connectionStart:theURL];
    }
}

@end

【问题讨论】:

  • 你发布的是self.receivedData还是_receivedData?您是否手动将对象分配给_receivedData
  • 你在其他地方发布吗?
  • 在 didReceiveData 中我调用[self.receivedData appendData:data]; 来附加来自 NSURLConnection 的数据。在 connectionDidFinishLoading 中,我通过[self.receivedData release];self.receivedData = nil; 发布它,我不在dealloc 中发布它。
  • 在 didReceiveData 中发布之前,我通过NSXMLParser *nsXmlParser = [[NSXMLParser alloc] initWithData:self.receivedData];UIImage *thumbImage = [[UIImage alloc] initWithData:self.receivedData]; 使用它。此属性不再使用。

标签: iphone objective-c properties retain


【解决方案1】:

不要调用[self.receivedData release] - 这会使内部指针悬空。保留财产的全部意义在于它释放了自己。只需self.receivedData = nil

【讨论】:

    【解决方案2】:

    这是你的问题:

        [self.receivedData release];
        self.receivedData = nil;
    

    您将两次释放该属性(第一次显式,第二次通过分配 nil 隐式)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多