【问题标题】:When release methods local variables in Obj-C当在 Obj-C 中释放方法局部变量时
【发布时间】:2011-10-26 21:44:06
【问题描述】:

我正在开发一个 iPhone 应用程序,我刚刚创建了这个方法(它在一个单例类中):

- (NSDictionary *)getLastPosts
{
    SBJsonParser *parser = [[SBJsonParser alloc] init];

    NSURLRequest *request = [NSURLRequest requestWithURL:
                             [NSURL URLWithString:http://example.org/last/]];

    NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

    NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];

    NSDictionary *data_dict = [parser objectWithString:json_string error:nil];

    // release stuff
    [parser release];
    [request release];
    [response release];
    [json_string release];

    return data_dict;
}

我是一个新手 obj-c 开发人员,所以我不确定这两件事:

  • 方法末尾的四个vars发布是否正确?
  • 何时我应该发布 NSDictionary data_dict

更新 1

如果data_dictNSDictionary *data_dict = [[NSDictionary alloc] init],我应该什么时候发布它?

更新 2

在调用者中我有这个:

- (void)callerMethod
{
    NSDictionary *tmpDict = [mySingleton getLastPosts];
    NSLog(@"retain count: %d", [tmpDict retainCount]);
}

调试控制台打印:

retain count: 2
  • 为什么“Xcode Analyze”会告诉我这几行?
  • 为什么保留计数是 2?

【问题讨论】:

  • 你将data_dict返回给另一个方法,所以你不能在这个方法中释放它。你应该autorelease它,所以接收方法仍然有数据。用你用的方法,已经自动释放了。
  • 如果 data_dict 是使用[[NSDictionary alloc] init] 获得的,它的保留计数为 1,您需要稍后自动释放它。如果它是通过[parser objectWithString:json_string error:nil]; 获得的,它已经自动释放,你应该在不自动释放的情况下返回它。
  • 哦,是的,对。这是一个错误 :) 它的保留计数为 2,因为第一个所有者是单例的方法,而另一个所有者是视图控制器中的调用者?
  • 我觉得retainCount这个方法真的不能信任,静态分析器应该更值得信任。据我所知,字典是从getLastPosts 返回的,保留计数为 1,但“虚拟”(我的定义)保留计数为 0,因为已经调用了 autorelease,并且在某个时候池会释放它。如果此时保留计数为 2,您应该在 tmpDict 上调用 retain。
  • stackoverflow.com/questions/2640568/… 解释了为什么不能依赖 retainCount。

标签: iphone objective-c ios memory-management


【解决方案1】:

一般来说,最好释放不再需要的对象。 但要记住 - 只需要释放初始化中有allocnewcopy 的东西。否则它们已经被自动释放了。

所以,可以释放解析器,不可以释放请求,不可以释放响应,可以释放json_string。

【讨论】:

  • 您只是忘记添加data_dictautorelease 并且不应在此范围内发布,因为稍后将由nsautoreleasepool 发布
【解决方案2】:
SBJsonParser *parser = [[SBJsonParser alloc] init];

您调用了 init,然后您拥有该实例,您需要释放它。

NSURLRequest *request = [NSURLRequest requestWithURL:
[NSURL URLWithString:http://example.org/last/]];

您调用了一个类方法,该方法返回一个自动释放的实例,该实例将被添加到自动释放轮询中。

NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];

自动释放。

NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];

你调用了 init,你需要释放它。

NSDictionary *data_dict = [parser objectWithString:json_string error:nil];

返回的实例,自动释放。

因此你只需要释放其中两个:

[parser release];
[json_string release];

如果是NSDictionary *data_dict = [[NSDictionary alloc] init],那么您需要自己自动释放它:惯例是方法返回的任何实例都是自动释放的。

顺便说一句,通过自动释放它,您可以确保它在自动释放池被清空之前可用(除非您在其上调用释放)。

自动释放它:

return [data_dict autorelease];

【讨论】:

  • 感谢您的解释。在我使用我的 var 之前,自动释放池可能会耗尽吗?
  • 自动释放池在创建它的事件结束时被耗尽,所以它不应该。 Autorelease 肯定会保留您的对象,以便您有机会从需要它的代码中保留它。有关自动释放池的更多实用信息,请参阅这一系列 youtube 视频:youtube.com/watch?v=59bDaCydrH4&feature=related
  • 每个 init 都需要释放,否则实例会泄漏,当您从方法中获取自动释放的对象时,释放就是一颗定时炸弹:它不会像释放那样立即发生。延迟发布。当你想保留它时,你仍然应该在实例上调用retain,然后在完成后调用release。它不会立即被释放,它的保留计数仍然为 1。当自动释放池被清空时,它会在实例上调用释放,使保留计数为 0 并导致它被释放。
  • 非常感谢 doppioslash(是意大利用户名吗?)。祝你有美好的一天。
  • 是的! Doppio的意思是双重的。不客气,编码愉快! :)
【解决方案3】:

释放parserjson_string 是正确的,因为它们是使用包含“alloc”的方法创建的。释放其他是不正确的,因为它们是自动释放的。

您不必在此方法中释放data_dict,因为它是自动释放的。

请阅读Objective-C memory management rules

【讨论】:

  • 抱歉,init 不是类方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-01-03
  • 2011-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多