iOS:理解释放 NSString 的问题
我有以下代码:
+ (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];
}
问题是additionalQuery-NSString 的发布。 当我运行此代码时,它以 BAD-ACCES-EXCEPTION 结束,
[additionalQuery release];
一旦我将其注释掉,代码就可以正常工作。
现在,尽管很简单,运行我的应用程序而不使用这行代码可能没问题,但我的问题是:我错了什么?
我在 IF 子句中生成 NSString,然后我只能在 IF 子句中释放它。但为什么我在那里遇到错误?
I have following code:
+ (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];
}
The problem is the Release of the additionalQuery-NSString.
When I run this code, it ends with an BAD-ACCES-EXCEPTION for the
[additionalQuery release];
As soon as I comment this out, the code works fine.
Now, as simple as it is, run my app without this line of code could be fine, but my question is: What do Im wrong?
I generate an NSString in an IF-Clause, then I CAN only release it in the IF-Clause. But why I got a Error there?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
看看您创建的additionalQuery
使用 stringWithFormat 您创建了一个自动释放的 NSString 对象。您不得根据内存管理规则手动释放它,因为您不拥有它。
您只拥有使用 alloc] init..] 创建的东西,或者名称中带有 new.. 或 create.. 的东西,当然,如果您执行诸如 mutableCopy 之类的副本。
因此 [additionalQuery release] 会导致过度释放对象,因此这是一个错误的访问
Look at your creation of additionalQuery
With stringWithFormat you create an autoreleased NSString object. You MUST NOT release it manually according to the Memory Management rules since you don't own it.
You own only things you created with alloc] init..] or something with new.. or create.. in the name and of course if you do a copy such as mutableCopy.
So [additionalQuery release] causes over-releasing an object and thus it is a BAD ACCESS
问题在于字符串实例是使用以类名 (
stringWithFormat
) 开头的类方法创建的。按照惯例,这些类型的类方法返回一个自动释放的对象,使您不必担心释放它们,除非您专门对返回的对象调用retain。如果您确实想对对象执行自己的内存管理,则可以将行:更改
为以下任一内容:
或:
另外,此代码还存在其他几个问题。
不应释放
username
变量,因为按照惯例,从GetUsernameFromNSDefaults
获取该变量的方法应返回一个自动释放的对象。根据一般经验,除init
方法之外的任何方法都应返回自动释放的对象。对于不了解代码库的程序员来说,如果不遵循这些约定,就很难拾取并修改它。request
变量不需要释放,因为它是使用返回自动释放对象 (requestWithURL) 的类方法创建的。如果您希望代码保留它,请对其调用retain
,或使用方法initWithURL:
。此外,
results
变量不是由您保留的,因此无需释放它。The problem is that the string instance is created using a class method that starts with the class name (
stringWithFormat
). By convention, these types of class methods return an autoreleased object, freeing you from worrying about releasing them unless you specifically call retain on the returned object.If you do want to perform your own memory management on the object, you could change your line:
to either of the following:
or:
As an aside, you also have several other issues with this code.
The
username
variable should not be released because again, by convention, the method you get it fromGetUsernameFromNSDefaults
should return an autoreleased object. As a general rule of thumb, any method other than aninit
method should return an autoreleased object. It would become very difficult for a programmer not knowledgable with the codebase to pick it up and modify without following these conventions.The
request
variable does not need to be released because it is created with a class method that returns an autoreleased object (requestWithURL). If you wanted it to be retained by your code, either callretain
on it, or use the methodinitWithURL:
.Additionally, the
results
variable is not retained by you, so there is no need to release it.您不必手动释放它,它会自动释放。 (
[NSString stringWithFormat:]
与[NSString initWithString:]
)You don't have to release it manually, it will get autoreleased. (
[NSString stringWithFormat:]
vs.[NSString initWithString:]
)我可以看到,
additionalQuery
从未被保留。 (stringWithFormat
执行自动释放,因此不算在内。)additionalQuery
was never retained, that I can see. (stringWithFormat
does an autorelease, so it doesn't count.)当您使用便捷方法(不以 new、alloc 或 copy 开头的方法)创建对象实例时,返回的对象将自动释放。换句话说,您不需要显式释放它。
当您调用 stringWithFormat 方法时,它会返回一个自动释放的 NSString。随后,您继续释放此 NSString 实例...
这会将释放消息发送到additionalQuery 实例。由于它是一个自动释放的对象,因此它被添加到(通常)位于主事件线程上的自动释放池中。该池经常被耗尽,并随后向它包含的每个对象发送一条释放消息。因此,当对象自动释放时,池将在为您发送释放消息后进行处理。
这里的 EXC_BAD_ACCESS 是您释放 NSString 的结果 - 在池耗尽之前将其保留计数降至 0。然后池被清空并尝试向已释放的对象发送消息。
When you create an instance of an object using a convenience method (one that does not begin with new, alloc or copy) the returned object is autoreleased. In other words you do not need to explicitly release it.
When you invoke the stringWithFormat method it returns an autoreleased NSString. You subsequently go on to release this NSString instance...
This sends the release message to the additionalQuery instance. As it's an autoreleased object it is added to an autorelease pool which lives (usually) on the main event thread. This pool is drained frequently and subsequently sends a release message to each of the objects it contains. Hence when an object is autoreleased the pool will look after sending the release message for you.
Your EXC_BAD_ACCESS here is a result of you releasing the NSString - dropping its retain count to 0 prior to the pool draining. The pool is then drained and attempts to send a message to a deallocated object.
您已在此处指定 [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-
这真的会对你有帮助...
you have specified here [NSString stringWithFormat:@"login_username=%@&login_password=%@", username, password];
means this method will handle allocation and release for your string so "you do not need to release it" hence remove the line [additionalQuery release];
also, u are not allocating string for username and password hence no need to release it .
if you write Nsstring *username = [[NSString alloc]init]; then you need to release it..
for more information regarding Memory Management refer
http://marcelsite.heroku.com/posts/5-iPhone-s-alloc-init-new-retain-release-autorelease-copy-
this will really help you...