Note: This similar SO question talks about how to build the same class, but doesn't address my memory management issues related to using the class.
I would like to use sendAsynchronousRequest:queue:completionHandler:
, however I need to support iOS 4.2. Thus, I created a custom class called JCURLRequest
that uses NSURLConnection
and generates an nice interface:
- (void)sendRequest:(NSURLRequest *)request
responseHandler:(JCURLResponseHandler)responseHandler;
I have a question about using this class (I'm in ARC memory management):
- When I create my JCURLRequest object do i need to retain a reference to that object? Or can I just "fire and forget it"?
Note: I understand the basics of ARC - if you have a pointer to an object, it will be kept alive, if there are no more pointers to an object, it will be release in the next auto-release pool.
Thus, I want to know - can I call it like (1) or do i need to use (2)
(1)
JCURLRequest *jcURLRequest = [[JCURLRequest alloc] init];
[jcURLRequest sendRequest:myRequest
responseHandler:^(NSData *data, NSError *error) { ... }];
// Assuming I don't maintain a reference to jcURLRequest after this
(2)
// Assume @property (strong) JCURLRequest *jcURLRequest;
// @synthesize jcURLRequest = _jcURLRequest;
self.jcURLRequest = [[JCURLRequest alloc] init];
[self.jcURLRequest sendRequest:myRequest
responseHandler:^(NSData *data, NSError *error) { ... }];
NSURLConnection
uses an asynchronous callback, so my thought is that I have to use (2). This is because - by the time the delegate callback "calls back", the jcURLRequest instance could have been cleaned up in an auto-release pool.
I'm confused though, because I've tested with (1) and it "seems" to work fine. But, my thought is that maybe it's just coincidence that it's working- ie. really there are no more valid pointers to the jcURLRequest object but the iOS just hasn't gotten around to deallocating it.
Below is the full JCURLRequest
class for reference
// JCURLRequest.h
#import <Foundation/Foundation.h>
typedef void (^JCURLResponseHandler) (NSData *data, NSError *error);
@interface JCURLRequest : NSObject
- (void)sendRequest:(NSURLRequest *)request responseHandler:(JCURLResponseHandler)responseHandler;
@end
// JCURLRequest.m
#import "JCURLRequest.h"
@interface JCURLRequest ()
{
JCURLResponseHandler responseHandler;
}
@property (strong, nonatomic) NSMutableData *responseData;
@end
@implementation JCURLRequest
@synthesize responseData = _responseData;
#pragma mark - Public API
- (void)sendRequest:(NSURLRequest *)request responseHandler:(JCURLResponseHandler)handler
{
responseHandler = [handler copy];
dispatch_async(dispatch_get_main_queue(), ^{
__unused NSURLConnection *connectionNotNeeded = [[NSURLConnection alloc] initWithRequest:request delegate:self];
});
}
#pragma mark - Private API
- (NSMutableData *)responseData
{
if (!_responseData)
{
_responseData = _responseData = [[NSMutableData alloc] initWithLength:0];
}
return _responseData;
}
#pragma mark - URL Connection Methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[self.responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[self.responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
responseHandler(nil, error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
responseHandler([NSData dataWithData:self.responseData], nil);
}
@end