I have read Apple's Blocks Programming Topics and my due diligence searching online, but I am still unclear if I am implementing my blocks correctly. I have an array of clients as a property that is populated when an NSNotification is sent. Clients is used as a tableview data source. The code below works, but I am curious if it is putting self in a retaining cycle. Should I do something like __block id theClients = self.clients; and then reference theClients inside the block?
@property (strong, nonatomic) NSMutableArray *clients;
NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
__block id observer = [notifyCenter addObserverForName:queryHash
object:nil
queue:[[NSOperationQueue alloc] init]
usingBlock:^(NSNotification* notification){
// Explore notification
if ([[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0]) {
NSArray *rows = [[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0];
if (self.clients)
{
self.clients = nil;
}
self.clients = [[NSMutableArray alloc] initWithCapacity:rows.count];
for (NSDictionary *row in rows) {
[self.clients addObject:row];
}
} else {
NSLog(@"CLIENTS ERROR Returned: %@",[notification.userInfo objectForKey:kerrorReturnKey]);
}
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}];
There is no problem in accessing the clients property because it is a strong (i.e. retained) property. So you don't need the __block here.
One problem can be that self might not exist anymore when the notification is sent. Then you would access the deallocated object and the app can crash! To avoid that you should remove the observer in the dealloc method.
The __block before id observer is definitely required !
EDIT:
In iOS 5 you can safely capture self using a weak reference:
__weak id weakSelf = self;
Then inside the block you can safely use weakSelf.clients. The variable weakSelf will turn into nil automatically when the object is deallocated.
Yes, you have a retain cycle, at least until the notification occurs. When you access the clients ivar in the block, the block will retain self. It will be retained by the block in notification center until the notification occurs (since you remove the observer at the end of the block). If that's not desirable in your case, you can use a weak reference to self.
NSNotificationCenter *notifyCenter = [NSNotificationCenter defaultCenter];
__weak id weakSelf = self;
id observer = [notifyCenter addObserverForName:queryHash
object:nil
queue:[[NSOperationQueue alloc] init]
usingBlock:^(NSNotification* notification) {
if (weakSelf) {
if ([[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0]) {
NSArray *rows = [[notification.userInfo objectForKey:kdatasetReturnKey] objectAtIndex:0];
if (weakSelf.clients)
{
weakSelf.clients = nil;
}
weakSelf.clients = [[NSMutableArray alloc] initWithCapacity:rows.count];
for (NSDictionary *row in rows) {
[weakSelf.clients addObject:row];
}
} else {
NSLog(@"CLIENTS ERROR Returned: %@",[notification.userInfo objectForKey:kerrorReturnKey]);
}
}
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}];
I don't see any reason you need to __block qualify observer.
It's also not clear you're getting anything out of using the block-based API here. If you don't want to worry about the potential retain cycle, you could just use addObserver:selector:name:object: and put the body of your notification callback in an instance method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With