From a2f9956d00e58c855cd79edb8b8c35e3fed49251 Mon Sep 17 00:00:00 2001 From: Mazyad Alabduljaleel Date: Mon, 23 Feb 2015 10:38:33 +0400 Subject: [PATCH] Fix major memory leaks in iOS http request ... and other small fixes Brief: 1. In iOS, whenever you have a new spawned thread with its own run loop (i.e. while true), you must wrap it with an autorelease pool, so it cleans up the objects at the end of each loop cycle. 2. There were a few "alloc" and "new" objects that weren't released. 3. The HttpAsync class itself was missing dealloc, also property assignment should use `self.property` so the previous value gets released as appropriate. 4. Resolved a small warning **NOTE**: I have a cocos2d-x game that heavily relies on the HTTP requests, with cookies, but without SSL, so I couldn't test the SSL. I haven't tested the cookies and SSL yet, but for starters, these improvements are meant to fix the memory issues only, not the logic. --- cocos/network/HttpAsynConnection.m | 32 ++++++++++++++++++++++++------ cocos/network/HttpClient-ios.mm | 16 +++++++-------- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/cocos/network/HttpAsynConnection.m b/cocos/network/HttpAsynConnection.m index 63892ff282..2d8ab75ce0 100755 --- a/cocos/network/HttpAsynConnection.m +++ b/cocos/network/HttpAsynConnection.m @@ -24,6 +24,12 @@ #import "HttpAsynConnection.h" +@interface HttpAsynConnection () + +@property (readwrite) NSString *statusString; + +@end + @implementation HttpAsynConnection @synthesize srcURL; @@ -38,14 +44,28 @@ @synthesize finish; @synthesize runLoop; +- (void)dealloc +{ + [srcURL release]; + [sslFile release]; + [responseHeader release]; + [responseData release]; + [statusString release]; + [responseError release]; + [conn release]; + [runLoop release]; + + [super dealloc]; +} + - (void) startRequest:(NSURLRequest *)request { NSLog(@"Starting to load %@", srcURL); finish = false; - responseData = [NSMutableData new]; + self.responseData = [NSMutableData new]; getDataTime = 0; - responseError = nil; + self.responseError = nil; // create the connection with the target request and this class as the delegate self.conn = [[NSURLConnection alloc] initWithRequest:request @@ -71,12 +91,12 @@ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; //NSLog(@"All headers = %@", [httpResponse allHeaderFields]); - responseHeader = [[httpResponse allHeaderFields] copy]; + self.responseHeader = [[httpResponse allHeaderFields] copy]; responseCode = httpResponse.statusCode; - statusString = [[NSHTTPURLResponse localizedStringForStatusCode:responseCode] copy]; + self.statusString = [[NSHTTPURLResponse localizedStringForStatusCode:responseCode] copy]; if(responseCode == 200) - statusString = @"OK"; + self.statusString = @"OK"; /*The individual values of the numeric status codes defined for HTTP/1.1 | “200” ; OK @@ -118,7 +138,7 @@ didFailWithError:(NSError *)error { //NSLog(@"Load failed with error %@", [error localizedDescription]); - responseError = [error copy]; + self.responseError = [error copy]; finish = true; } diff --git a/cocos/network/HttpClient-ios.mm b/cocos/network/HttpClient-ios.mm index 9a63e5e265..23a4f52bff 100644 --- a/cocos/network/HttpClient-ios.mm +++ b/cocos/network/HttpClient-ios.mm @@ -77,8 +77,8 @@ void HttpClient::networkThread() { auto scheduler = Director::getInstance()->getScheduler(); - while (true) - { + while (true) @autoreleasepool { + HttpRequest *request; // step 1: send http request if the requestQueue isn't empty @@ -224,16 +224,16 @@ static int processTask(HttpRequest *request, NSString* requestType, void *stream } } - HttpAsynConnection *httpAsynConn = [HttpAsynConnection new]; + HttpAsynConnection *httpAsynConn = [[HttpAsynConnection new] autorelease]; httpAsynConn.srcURL = urlstring; httpAsynConn.sslFile = nil; - NSString *sslFile = nil; + if(!s_sslCaFilename.empty()) { long len = s_sslCaFilename.length(); long pos = s_sslCaFilename.rfind('.', len-1); - [sslFile initWithUTF8String:s_sslCaFilename.substr(0, pos-1).c_str()]; - httpAsynConn.sslFile = sslFile; + + httpAsynConn.sslFile = [NSString stringWithUTF8String:s_sslCaFilename.substr(0, pos-1).c_str()]; } [httpAsynConn startRequest:nsrequest]; @@ -282,7 +282,7 @@ static int processTask(HttpRequest *request, NSString* requestType, void *stream //handle response header NSMutableString *header = [NSMutableString new]; - [header appendFormat:@"HTTP/1.1 %ld %@\n", httpAsynConn.responseCode, httpAsynConn.statusString]; + [header appendFormat:@"HTTP/1.1 %ld %@\n", (long)httpAsynConn.responseCode, httpAsynConn.statusString]; for (id key in httpAsynConn.responseHeader) { [header appendFormat:@"%@: %@\n", key, [httpAsynConn.responseHeader objectForKey:key]]; @@ -335,7 +335,7 @@ static void processResponse(HttpResponse* response, char* errorBuffer) break; default: - CCASSERT(true, "CCHttpClient: unkown request type, only GET and POSt are supported"); + CCASSERT(true, "CCHttpClient: unkown request type, only GET, POST, PUT, DELETE are supported"); break; }