2009-03-09 12 views
8

widzę awarię, co dzieje się 10 lub 20 sekund po żądanie POST robię zakończył (didReceiveResponse, didReceiveData i connectionDidFinishLoading wszystko ogień dobrze przed katastrofą dzieje).iPhone SDK: księgowania NSData z wynikami NSMutableURLRequest w tajemniczej katastrofie

Jest to kod używam, aby wniosek:

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]; 

Co jest bardzo dziwne o tej katastrofie jest taka: jeśli I nie nazywaj setHTTPBody z moim NSData obiektu, setValue:@"application/json" dla Content-Type i setValue:requestDataLengthString dla Content-Length, zdarza się katastrofa nie. Jestem całkowicie zakłopotany, co się dzieje. O ile mogę powiedzieć, krach jest bezpośrednio związany z wysłaniem obiektu NSData z moją prośbą. Kiedy psuje, górne elementy stosu wywołań do katastrofy (EXEC_BAD_ACCESS) są następujące:

  • objc_msgSend
  • CFRelease
  • HTTPMessage::~HTTPMessage
  • _CFRelease
  • HTTPWriteFilter::~HTTPWriteFilter

Czy ktoś może pomyśleć o czymś, co mogę robić źle? Brakuje mi całkowicie tego, co robię źle, jak to naprawić, lub jak sobie z tym poradzić. Czy istnieje lepszy sposób na dane POST niż sposób, w jaki robię?

+0

Wystarczy, aby spróbować czegoś: czy nadal się zawiesza, jeśli usuniesz linię [requestData release]? – squelart

Odpowiedz

7

Jesteś rację, że problem jest z obiektem NSData.Jesteś przeznaczając go tak:

NSData* requestData = [jsonData dataUsingEncoding:NSUTF8StringEncoding]; 

Zgodnie z zasadami określonymi w Memory Management Programming Guide for Cocoa, nie jesteś właścicielem tych danych, więc nie powinno być wywołanie release na nim później. dataUsingEncoding połączeń autorelease, więc obiekt będzie release d następnym razem, gdy basen autorelease drenuje. Ponieważ dodajesz dodatkową wartość release, pula autorelease będzie próbowała wykonać release obiekt, który został już zwolniony, co powoduje awarię.

+0

To było dokładnie to. Dziękuję Ci! –

5

Użytkownik zwolnił obiekt zwolniony automatycznie.

Usuń linię [requestData release]; Nie potrzebujesz tego. Powoduje to awarię, ponieważ dane są przez ciebie uwalniane, a następnie ponownie wysyłane, gdy wysyłane są dane, co jest zbyt dużą liczbą wydań.

Ogólnie rzecz biorąc, nie wywołuje się zwalniania obiektu, chyba że użytkownik go przydzieli, lub dokumenty wyraźnie mówią, że zwracany obiekt nie jest autoodrzucany. (co jest rzadkie).

Przy tym kodzie nie musisz się martwić, że używasz autorejestrowanego obiektu, jeśli chodzi o pamięć, bez względu na to, co robisz, pamięć pozostanie w pobliżu, dopóki podstawowy szkielet nie przesyła danych wzdłuż przewodu .

Nie wiem, czy istnieje lepszy sposób publikowania danych - kod, który wyglądasz dobrze, inny niż dane json jest prawdopodobnie duplikowany zarówno w ciągu znaków, jak iw obiekcie danych, ale w ilości danych, które wysyłanie może być niewielkie. Jeśli tak nie jest, powinieneś bezzwłocznie zwolnić ciąg jsonData zaraz po wykonaniu danych. (Co oznaczałoby, że ciąg jsonData musi pochodzić z wywołania alloc/init wraz z danymi). Lub nie rób jsonData jako ciąg, po prostu uczyń to jako dane nsmutable od samego początku, ale to może być niezręczne.

--Tom

+0

Cholerna autorelease :-) Myślę, że to ostatni raz, kiedy popełnię ten błąd, haha. Dziękuję Ci! –

1

Sprawdź również połączenie z [urlString release];. jeśli urlString został utworzony z czymś takim jak stringWithFormat lub stringwithString, nie powinieneś go zwolnić.