0

使用 xcode 分析器,我收到一个对象潜在泄漏的警告。这个警告令人困惑,我需要一些解释为什么我会收到这个错误。这是 mediaSources 保存指向相关对象的指针的代码:

在 .h 文件中,创建指向 MediaSources 类的指针并赋予保留属性:

@interface RootViewController : UIViewController <...>
{
    ...

    MediaSources                *mediaSources;

    ...
}

@property (nonatomic, retain)   MediaSources            *mediaSources;

.m 文件(rootViewController)中有一个可以多次调用的方法。因此,我在每个条目上释放对象并分配一个新对象。MediaSources 对象执行后台任务,所以在我知道它完成之前我不想释放它。如果我在分配类的行上使用 autoRelease,它会崩溃。:

-(void) getSelectedMediaSources
{
    [self setMediaSources: nil];    // release old stuff and nilify 
    [self setMediaSources: [[MediaSources alloc] init]]; 
    [self.mediaSources checkForMediaSourceUpdates];
}

同样在.m文件中,mediaSources也被合成并在dealloc中释放

@synthesize mediaSources;

...

- (void)dealloc {
    ...
    [mediaSources release];
    ...

    [super dealloc];
}

请解释我收到此警告的原因。我不明白怎么可能有泄漏。Dealloc 应该释放这个对象的最后一个副本。

响应 checkForMediaSourceUpdates 的代码请求。这将变得有点复杂,但以下是本质:

(void) checkForMediaSourceUpdates
{    
    NSString *s = [NSString  stringWithFormat:@"http://www.mywebsite.com/mediaSources/%@/mediaSources.plist", countryCode];

    NSURL *url = [NSURL URLWithString:s];
    NSURLRequest *req = [NSURLRequest requestWithURL:url  cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60.0];
    MyDownloader *d = [[MyDownloader alloc] initWithRequest:req];
    [self.connections addObject:d];
    [[NSNotificationCenter defaultCenter] addObserver:self  selector:@selector(checkForMediaSourceUpdatesDownloadFinished:) name:@"connectionFinished" object:d];
    [d.connection start];
    [d release];
}

-(void) checkForMediaSourceUpdatesDownloadFinished: (NSNotification *) n 
{
    MyDownloader *d = [n object];
    NSData *data = nil;
    if ([n userInfo]) {
        NSLog(@"In checkForMediaSourceUpdatesDownloadFinished: MyDownloader returned an error");
    }
    else {
        data = [d receivedData];

        // do something with the data
    }
}

myDownloader 类执行输入 NSURLRequest 中指定的文件下载。完成下载后,该类会生成一个名为“connectionFinished”的NSNotification。此类的用户必须注册此通知并处理此类的所有清理操作。如果下载失败,该类将生成一个 NSNotification,也称为“connectionFinished”,但添加了指示发生错误的 userInfo。同样,此类的用户必须注册此通知并处理此类的所有清理操作。

4

3 回答 3

4

根据定义,您将自动释放的对象传递给合成的 setter。setter 本身保留了对象,因此以下行是错误的:

[self setMediaSources: [[MediaSources alloc] init]]; 

它应该是:

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

此外,您之前也不需要调用您的二传手nil。当通过 setter 设置不同的对象时,旧对象被释放。合成的二传手看起来像:

- (void) setMediaSources:(MediaSources *)mediaSources {
  if (_mediaSources != mediaSources) {
    [_mediaSources release];
    _mediaSources = [mediaSources retain];
  }
}

问题是:为什么你需要MediaSource在每次调用时分配一个新的getSelectedMediaSources?解除分配 autoreleased 时,您期望发生什么崩溃MediaSource?您是将其设置为另一个对象的委托还是将其注册到一个NSNotificationCenter?如果是这样,请不要忘记取消委托或将其从通知中心删除。

于 2013-05-21T18:41:07.597 回答
3

正如其他答案中已经提到的,您应该autorelease像这样将一个 d 实例传递给 setter:

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

您因为这样做而看到的崩溃似乎源于您在checkForMediaSourceUpdates. 如果要在此方法中进行后台处理,则应确保self在后台任务的整个持续时间内保持有效。[self retain];在开始和[self release];结束时手动调用是完全有效的。(注意:如果您从块中引用它,GCD块会自动保留/释放对象)。self

编辑:我希望你现在知道这个问题,mau称之为。执行请求时,实例上只有一个保留计数(按RootViewController对象) 。MediaSources在请求完成之前,您再次调用该方法,导致MediaSources对象被释放。因此,当请求完成并NSNotification尝试发送回调消息时,应用程序崩溃,因为观察者实例已经消失。

有两种方法可以解决这个问题(使用更适合您的情况的方法):

  1. 要么添加并[self retain];在末尾checkForMediaSourceUpdates[self release];checkForMediaSourceUpdatesDownloadFinished:
  2. 或者,添加[[NSNotificationCenter defaultCenter] removeObserver: self].-[MediaSources dealloc]

顺便说一句,您应该考虑一下why do you need to allocate a new MediaSource on every call to getSelectedMediaSources?为什么每次您可能有正在运行的请求时都启动一个新请求。你的设计有很大的问题。

于 2013-05-21T19:59:48.433 回答
0
[self setMediaSources: [[MediaSources alloc] init]]; 

您将两次保留新的 MediaSources 对象,一次是使用alloc,另一次是使用setMediaSources。你只释放一次。

尝试:

[self setMediaSources: [[[MediaSources alloc] init] autorelease]]; 

从评论跟进:

是的,您可以直接设置变量,但这并不能解决您的根本问题。听起来您现有的代码因为额外的保留而有效,并且在您平衡保留/释放时失败。您需要找出谁在保留对旧 mediaSources 对象的弱引用,并在释放它之前中断该引用。

于 2013-05-21T18:42:27.610 回答