If any of you do a lot of work with blocks and completion handlers, maybe you can help with what I am trying to do here.
I am trying to switch around some classes to use blocks instead of delegate callbacks. I have a NBSURLConnection class that downloads a resource from the network. Instead of setting a delegate, the NBSURLConnection is created with a completion handler. This completion handler is called when the connection is finished or fails.
The NBSModel that creates the NBSURLConnection passes in a block that the NBSURLConnection will need to copy to the heap so that it can call it later. If the block that is passed references an instance variable of the NBSModel, the NBSModel will be retained when the block is copied:
NBSModel retains NBSURLConnection
NBSURLConnection retains block
block retains NBSModel
What is the best way to avoid this problem?
I am trying to switch around some classes to use blocks instead of delegate callbacks. I have a NBSURLConnection class that downloads a resource from the network. Instead of setting a delegate, the NBSURLConnection is created with a completion handler. This completion handler is called when the connection is finished or fails.
The NBSModel that creates the NBSURLConnection passes in a block that the NBSURLConnection will need to copy to the heap so that it can call it later. If the block that is passed references an instance variable of the NBSModel, the NBSModel will be retained when the block is copied:
NBSModel retains NBSURLConnection
NBSURLConnection retains block
block retains NBSModel
What is the best way to avoid this problem?
Code:
typedef void (^NBSURLConnectionCompletionHandler)(NSData *data, NSURLResponse *response, NSError *error);
@interface NBSURLConnection : NSObject
{
@private
NBSURLConnectionCompletionHandler myCompletionHandler;
NSMutableData *myData;
NSURLConnection *myConnection;
NSURLResponse *myResponse;
}
#pragma mark -
- (void)cancel;
- (id)initWithRequest:(NSURLRequest *)request withCompletionHandler:(NBSURLConnectionCompletionHandler)completionHandler;
@end
Code:
#import "NBSURLConnection.h"
@implementation NBSURLConnection
#pragma mark -
#pragma mark NSObject
#pragma mark -
- (void)dealloc
{
Block_release(myCompletionHandler);
[myData release];
[myConnection release];
[myResponse release];
[super dealloc];
}
#pragma mark -
#pragma mark NBSURLConnection
#pragma mark -
- (void)cancel
{
[myConnection cancel];
}
- (id)initWithRequest:(NSURLRequest *)request withCompletionHandler:(NBSURLConnectionCompletionHandler)completionHandler
{
self = [self init];
if (self)
{
myCompletionHandler = Block_copy(completionHandler);
myConnection = [[NSURLConnection alloc] initWithRequest: request delegate: self];
}
return self;
}
#pragma mark -
#pragma mark NSURLConnectionDelegate
#pragma mark -
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
myCompletionHandler(nil, myResponse, error);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
myCompletionHandler(myData, myResponse, nil);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
if (myData == nil)
{
myData = [[NSMutableData alloc] init];
}
[myData appendData: data];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
if (myResponse != response)
{
[myResponse release];
myResponse = [response copy];
}
[myData setLength: 0];
}
@end
Code:
@class NBSURLConnection;
@interface NBSModel : NSObject
{
@private
NBSURLConnection *myConnection;
NSData *myData;
}
#pragma mark -
- (id)initWithURL:(NSURL *)url;
@end
Code:
#import "NBSModel.h"
#import "NBSURLConnection.h"
@implementation NBSModel
#pragma mark -
#pragma mark NSObject
#pragma mark -
- (void)dealloc
{
[myConnection cancel];
[myConnection release];
[myData release];
[super dealloc];
}
#pragma mark -
#pragma mark NBSModel
#pragma mark -
- (id)initWithURL:(NSURL *)url
{
self = [self init];
if (self)
{
NSURLRequest *newRequest = [[NSURLRequest alloc] initWithURL: url];
if (newRequest)
{
myConnection = [[NBSURLConnection alloc] initWithRequest: newRequest withCompletionHandler: ^(NSData *data, NSURLResponse *response, NSError *error) {
myData = [data copy];
}];
[newRequest release];
}
}
return self;
}
@end