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.
This commit is contained in:
Mazyad Alabduljaleel 2015-02-23 10:38:33 +04:00
parent a303142da5
commit a2f9956d00
2 changed files with 34 additions and 14 deletions

View File

@ -24,6 +24,12 @@
#import "HttpAsynConnection.h" #import "HttpAsynConnection.h"
@interface HttpAsynConnection ()
@property (readwrite) NSString *statusString;
@end
@implementation HttpAsynConnection @implementation HttpAsynConnection
@synthesize srcURL; @synthesize srcURL;
@ -38,14 +44,28 @@
@synthesize finish; @synthesize finish;
@synthesize runLoop; @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 - (void) startRequest:(NSURLRequest *)request
{ {
NSLog(@"Starting to load %@", srcURL); NSLog(@"Starting to load %@", srcURL);
finish = false; finish = false;
responseData = [NSMutableData new]; self.responseData = [NSMutableData new];
getDataTime = 0; getDataTime = 0;
responseError = nil; self.responseError = nil;
// create the connection with the target request and this class as the delegate // create the connection with the target request and this class as the delegate
self.conn = [[NSURLConnection alloc] initWithRequest:request self.conn = [[NSURLConnection alloc] initWithRequest:request
@ -71,12 +91,12 @@
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
//NSLog(@"All headers = %@", [httpResponse allHeaderFields]); //NSLog(@"All headers = %@", [httpResponse allHeaderFields]);
responseHeader = [[httpResponse allHeaderFields] copy]; self.responseHeader = [[httpResponse allHeaderFields] copy];
responseCode = httpResponse.statusCode; responseCode = httpResponse.statusCode;
statusString = [[NSHTTPURLResponse localizedStringForStatusCode:responseCode] copy]; self.statusString = [[NSHTTPURLResponse localizedStringForStatusCode:responseCode] copy];
if(responseCode == 200) if(responseCode == 200)
statusString = @"OK"; self.statusString = @"OK";
/*The individual values of the numeric status codes defined for HTTP/1.1 /*The individual values of the numeric status codes defined for HTTP/1.1
| 200 ; OK | 200 ; OK
@ -118,7 +138,7 @@
didFailWithError:(NSError *)error didFailWithError:(NSError *)error
{ {
//NSLog(@"Load failed with error %@", [error localizedDescription]); //NSLog(@"Load failed with error %@", [error localizedDescription]);
responseError = [error copy]; self.responseError = [error copy];
finish = true; finish = true;
} }

View File

@ -77,8 +77,8 @@ void HttpClient::networkThread()
{ {
auto scheduler = Director::getInstance()->getScheduler(); auto scheduler = Director::getInstance()->getScheduler();
while (true) while (true) @autoreleasepool {
{
HttpRequest *request; HttpRequest *request;
// step 1: send http request if the requestQueue isn't empty // 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.srcURL = urlstring;
httpAsynConn.sslFile = nil; httpAsynConn.sslFile = nil;
NSString *sslFile = nil;
if(!s_sslCaFilename.empty()) if(!s_sslCaFilename.empty())
{ {
long len = s_sslCaFilename.length(); long len = s_sslCaFilename.length();
long pos = s_sslCaFilename.rfind('.', len-1); 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]; [httpAsynConn startRequest:nsrequest];
@ -282,7 +282,7 @@ static int processTask(HttpRequest *request, NSString* requestType, void *stream
//handle response header //handle response header
NSMutableString *header = [NSMutableString new]; 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) for (id key in httpAsynConn.responseHeader)
{ {
[header appendFormat:@"%@: %@\n", key, [httpAsynConn.responseHeader objectForKey:key]]; [header appendFormat:@"%@: %@\n", key, [httpAsynConn.responseHeader objectForKey:key]];
@ -335,7 +335,7 @@ static void processResponse(HttpResponse* response, char* errorBuffer)
break; break;
default: 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; break;
} }