objective-c iPhone SDK:使用 NSMutableURLRequest 发布 NSData 导致神秘崩溃
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/628472/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
iPhone SDK: POSTing NSData with NSMutableURLRequest results in mysterious crash
提问by Rob
I'm seeing a crash that happens 10 or 20 seconds after a POST request I make has finished (didReceiveResponse, didReceiveDataand connectionDidFinishLoadingall fire well before the crash happens).
我看到的是一个POST请求我做结束后发生的10或20秒的崩溃(didReceiveResponse,didReceiveData而connectionDidFinishLoading所有消防在飞机坠毁前发生了好)。
This is the code I'm using to make the request:
这是我用来发出请求的代码:
NSURL* url = [[NSURL alloc] initWithString:urlString];
[urlString release];
NSData* requestData = [jsonData dataUsingEncoding:NSUTF8StringEncoding];
NSString* requestDataLengthString = [[NSString alloc] initWithFormat:@"%d", [requestData length]];
NSMutableURLRequest* request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:@"POST"];
[request setHTTPBody:requestData];
[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
[request setValue:requestDataLengthString forHTTPHeaderField:@"Content-Length"];
[request setTimeoutInterval:30.0];
[url release];
[requestData release];
[requestDataLengthString release];
m_URLConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[request release];
What's very odd about this crash is this: if I do not callsetHTTPBody with my NSDataobject, setValue:@"application/json"for Content-Typeand setValue:requestDataLengthStringfor Content-Length, the crash does nothappen. I'm completely perplexed as to what is happening. As far as I can tell, the crash is directly related to sending an NSDataobject with my request. When it does crash, the top elements in the call stack for the crash (EXEC_BAD_ACCESS) are the following:
什么是很奇怪这个碰撞是这样的:如果我不叫setHTTPBody我的NSData对象,setValue:@"application/json"为Content-Type和setValue:requestDataLengthString对Content-Length,碰撞也不会发生。我对正在发生的事情感到非常困惑。据我所知,崩溃与NSData使用我的请求发送对象直接相关。当它确实崩溃时,崩溃的调用堆栈中的顶部元素 ( EXEC_BAD_ACCESS) 如下:
objc_msgSendCFReleaseHTTPMessage::~HTTPMessage_CFReleaseHTTPWriteFilter::~HTTPWriteFilter
objc_msgSendCFReleaseHTTPMessage::~HTTPMessage_CFReleaseHTTPWriteFilter::~HTTPWriteFilter
Can anyone think of something I might be doing wrong? I'm completely at a loss for what I'm doing wrong, how to fix it, or how to work around it. Is there a better way to POST data than the way I'm doing?
谁能想到我可能做错了什么?我完全不知道我做错了什么,如何修复它,或者如何解决它。有没有比我正在做的方式更好的 POST 数据方式?
采纳答案by Adam Rosenfield
You are correct in that the problem is with your NSDataobject. You're allocating it like so:
你是对的,问题出在你的NSData对象上。你是这样分配的:
NSData* requestData = [jsonData dataUsingEncoding:NSUTF8StringEncoding];
According to the rules laid out in the Memory Management Programming Guide for Cocoa, you're not an owner of the data, so you shouldn't be calling releaseon it later on. dataUsingEncodingcalls autorelease, so the object will be released the next time the autorelease pool drains. Because you're adding an extra release, the autorelease pool is going to try to releasean object which has already been deallocated, which is causing the crash.
根据Cocoa 内存管理编程指南中规定的规则,您不是数据的所有者,因此您以后不应调用release它。 dataUsingEncoding调用autorelease,因此该对象将release在下一次自动释放池耗尽时变为d。因为您添加了一个额外的release,自动释放池将尝试release一个已经被释放的对象,这会导致崩溃。
回答by Tom Andersen
You released an auto released object.
你释放了一个自动释放的对象。
Remove the line [requestData release]; You don't need it. It causes the crash, since the data gets released by you, then released again when the data is done sending, which is one too many releases.
删除行 [requestData release]; 你不需要它。它会导致崩溃,因为数据被您释放,然后在数据发送完成后再次释放,这是一次太多的释放。
In general, you don't call release on an object unless you alloc it, or the docs explicitly say that the returned object is not autoreleased. (which is rare).
通常,除非您分配对象,否则您不会在对象上调用 release,或者文档明确说明返回的对象不是自动释放的。(这是罕见的)。
With this code, you don't need to worry that you are using an autoreleased object, as far as memory goes, no matter what you do, the memory will stay around until the underlying framework sends the data along the wire.
使用此代码,您无需担心您正在使用自动释放的对象,就内存而言,无论您做什么,内存都会一直存在,直到底层框架沿线路发送数据。
I don't know if there is a better way to post data - the code you have looks ok, other than the json data is likely duplicated in both a string and a data object, but the amount of data you are sending may be small. If it isn't you should expicitly release the jsonData string right after you make the data. (Which would mean that the jsonData string wuld have to be from an alloc/init call, along with the data). Or don't make the jsonData as a string, just make it as an nsmutable data right from the start, but that may be awkward.
我不知道是否有更好的方式来发布数据 - 你的代码看起来没问题,除了 json 数据可能在字符串和数据对象中重复,但你发送的数据量可能很小. 如果不是,您应该在制作数据后立即明确释放 jsonData 字符串。(这意味着 jsonData 字符串必须来自 alloc/init 调用以及数据)。或者不要将 jsonData 作为字符串,从一开始就将其作为 nsmutable 数据,但这可能很尴尬。
--Tom
——汤姆
回答by Rog
Check the call to [urlString release];too. if urlStringwas created with something such as stringWithFormator stringwithString, you should not release it.
检查呼叫[urlString release];太。如果urlString是用诸如stringWithFormator 之类的东西创建的stringwithString,你不应该释放它。

