【问题标题】:iOS: understanding Problem with release an NSStringiOS:理解发布 NSString 的问题
【发布时间】:2023-03-20 00:45:01
【问题描述】:

我有以下代码:

+ (NSDictionary*) JSONRequest: (NSString*)query andWithCredentials:(BOOL)withCredentials
{
if (withCredentials)
{
    NSString *username = [LoginHandler GetUsernameFromNSDefaults];
    NSString *password = [LoginHandler GetPasswordFromNSDefaults];
    NSString *additionalQuery = [NSString stringWithFormat:@"login_username=%@&login_password=%@", username, password];

    query = [NSString stringWithFormat:@"%@&%@", query, additionalQuery];

    [username release];
    [password release];
    [additionalQuery release]; 
}

NSURLRequest *request = [NSURLRequest requestWithURL:  
                         [NSURL URLWithString:query]];  

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

NSString *jsonString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *results = [jsonString JSONValue];
return results;

[request release];
[response release];
[jsonString release];
[results release];

}

问题是附加Query-NSString 的发布。 当我运行此代码时,它以

的 BAD-ACCES-EXCEPTION 结束
[additionalQuery release];

只要我注释掉,代码就可以正常工作。

现在,尽管很简单,但在没有这行代码的情况下运行我的应用程序也可以,但我的问题是:我做错了什么?

我在 IF 子句中生成一个 NSString,然后我 CAN 只在 IF 子句中释放它。但是为什么我会出现错误?

【问题讨论】:

    标签: iphone ios exception exc-bad-access


    【解决方案1】:

    看看你创建的附加查询

    NSString *additionalQuery = [NSString stringWithFormat:@"login_username=%@&login_password=%@", username, password];
    

    使用 stringWithFormat 你可以创建一个自动释放的 NSString 对象。由于您不拥有它,因此您不得根据内存管理规则手动释放它。

    你只拥有你用 alloc] init..] 创建的东西或用 new.. 或 create.. 命名的东西,当然还有如果你做了 mutableCopy 之类的副本。

    所以 [additionalQuery release] 会导致过度释放一个对象,因此它是一个 BAD ACCESS

    【讨论】:

      【解决方案2】:

      问题在于字符串实例是使用以类名 (stringWithFormat) 开头的类方法创建的。按照惯例,这些类型的类方法返回一个自动释放的对象,让您不必担心释放它们,除非您专门对返回的对象调用 retain。

      如果你确实想对对象执行自己的内存管理,你可以改变你的行:

      NSString *additionalQuery = [NSString stringWithFormat:
          @"login_username=%@&login_password=%@", username, password];
      

      到以下任一:

      NSString *additionalQuery = [[NSString alloc] initWithFormat:
          @"login_username=%@&login_password=%@", username, password];
      

      或:

      NSString *additionalQuery = [[NSString stringWithFormat:
          @"login_username=%@&login_password=%@", username, password] retain];
      

      顺便说一句,这段代码还有其他几个问题。

      1. 不应释放username 变量,因为按照惯例,从GetUsernameFromNSDefaults 获取它的方法应该返回一个自动释放的对象。作为一般经验法则,init 方法以外的任何方法都应该返回一个自动释放的对象。不了解代码库的程序员如果不遵循这些约定,就很难拿起和修改它。

      2. request 变量不需要释放,因为它是使用返回自动释放对象 (requestWithURL) 的类方法创建的。如果您希望代码保留它,请在其上调用 retain,或使用方法 initWithURL:

      3. 另外,results变量不是你保留的,所以不需要释放它。

      【讨论】:

        【解决方案3】:

        您不必手动释放它,它会自动释放。 ([NSString stringWithFormat:][NSString initWithString:]

        【讨论】:

          【解决方案4】:

          additionalQuery 从未保留,我可以看到。 (stringWithFormat 会自动释放,所以不算数。)

          【讨论】:

            【解决方案5】:

            当您使用便捷方法(不以 new、alloc 或 copy 开头的方法)创建对象的实例时,返回的对象会自动释放。换句话说,您不需要显式释放它。

            当您调用 stringWithFormat 方法时,它会返回一个自动释放的 NSString。您随后继续释放此 NSString 实例...

            [additionalQuery release];
            

            这会将释放消息发送到附加查询实例。由于它是一个自动释放的对象,它被添加到一个自动释放池中,该池(通常)位于主事件线程上。该池经常被耗尽,随后会向其中包含的每个对象发送释放消息。因此,当一个对象被自动释放时,池会为您发送释放消息。

            您的 EXC_BAD_ACCESS 是您释放 NSString 的结果 - 在池耗尽之前将其保留计数降至 0。然后池被耗尽并尝试向已释放的对象发送消息。

            【讨论】:

              【解决方案6】:

              你在这里指定了[NSString stringWithFormat:@"login_username=%@&login_password=%@", username, password];

              表示此方法将为您的字符串处理分配和释放,因此“您不需要释放它”因此删除 [additionalQuery release] 行;

              另外,你没有为用户名和密码分配字符串,因此不需要释放它。

              如果你写 Nsstring *username = [[NSString alloc]init];那么你需要释放它..

              有关内存管理的更多信息,请参阅

              http://marcelsite.heroku.com/posts/5-iPhone-s-alloc-init-new-retain-release-autorelease-copy-

              这真的会帮助你...

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-11-23
                • 1970-01-01
                • 2015-08-04
                • 1970-01-01
                • 1970-01-01
                • 2012-01-31
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多