dispatch_async Nested Block - ios

I am using dispatch_async method to execute task in main queue. But it causing retain cycle:
Following is the code snippet:
self.test = ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", self);
});
};
I am not able to get properly why it is creating retain cycle. As My controller does not have ownership of dispatch_async block.

Try using weakSelf:
__weak typeof(self) weakSelf = self;
self.test = ^{
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", weakSelf);
});
};

If you don't want the outer block to retain self, but want the inner block to be able to keep self alive once dispatched, maybe something like this:
typeof(self) __weak weakSelf = self;
self.test = ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%#", strongSelf);
});
}
};

Related

break retain cycle in a block nested in another block

Sometimes I use a block nested in another block, here is my code
- (void)test {
__weak typeof(self) weakSelf = self;
[self.viewSource fetchData:^(BOOL succeed, NSError * _Nonnull error, id _Nonnull data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf.dataSource disposalData:^{
// here is the strongSelf ok? do I have to do something to avoid retain cycle?
[strongSelf updateUI];
}];
}];
}
- (void)updateUI {
}
I doubt the inner block still has a retain cycle?
[strongSelf.dataSource disposalData:^{
[strongSelf updateUI];
}];
my question is what is the correct way to break the retain cycle in such situation?
here is the additional discussion, as many friend mentioned about this, if I remove __strong typeof(weakSelf) strongSelf = weakSelf;, the inner block has no retain cycle? Is it perfectly correct?
- (void)test {
__weak typeof(self) weakSelf = self;
[self.viewSource fetchData:^(BOOL succeed, NSError * _Nonnull error, id _Nonnull data) {
[weakSelf.dataSource disposalData:^{
[weakSelf updateUI];
}];
}];
}
- (void)updateUI {
}
I think you can just create new strong reference inside nested block, like this:
- (void)test {
__weak typeof(self) weakSelf = self;
[self.viewSource fetchData:^(BOOL succeed, NSError * _Nonnull error, id _Nonnull data) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf.dataSource disposalData:^{
__strong typeof(weakSelf) strongSelf = weakSelf; // <- new strong ref
[strongSelf updateUI];
}];
}];
}
It will override the first strongSelf in the nested block scope. And it will be only alive during the execution of the nested block without strong reference cycle created. I think so =)

How do you manage retain counts in nested dispatch queue blocks

In the following code, how would you avoid nested blocks increasing the retain count of 'self'.
This is how I avoid nested blocks
-(void)openSession {
[self.loginManager logInWithReadPermissions:#[#"user_photos"]
fromViewController:[self.datasource mediaAccountViewControllerForRequestingOpenSession:self]
handler:[self loginHandler]];
}
-(void(^)(FBSDKLoginManagerLoginResult *result, NSError *error))loginHandler {
__weak typeof (self) weakSelf = self;
return ^ (FBSDKLoginManagerLoginResult *result, NSError *error) {
__strong typeof(weakSelf) strongSelf = weakSelf;
if (error) {
[strongSelf.delegate mediaAccount:strongSelf failedOpeningSessionWithError:error];
} else if (result.isCancelled) {
[strongSelf.delegate mediaAccountSessionOpeningCancelledByUser:strongSelf];
} else {
[strongSelf.delegate mediaAccountDidOpenSession:strongSelf];
}
[strongSelf notifyWithCompletion:[strongSelf completionHandler]]
};
}
-(void)notifyWithCompletion:(void(^)(void))completion {
[self notify];
completion();
}
-(void(^)(void))completionHandler {
return ^ {
//do something
};
}
But how do you avoid many nested blocks, which is often the case when you use GCD within a block ?
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self parseLoadsOfData];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateUI];
});
});
Are there retain cycles here ?
__weak typeof(self) *weakSelfOuter = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
__strong typeof(self) *strongInnerSelf1 = weakSelfOuter;
[strongInnerSelf1 parseLoadsOfData];
__weak typeof(self) *weakInnerSelf = strongInnerSelf1;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(self) *strongInnerSelf2 = weakInnerSelf;
[strongInnerSelf2 updateUI];
});
});

ios recursive call with block leaks memory

I am calling a function recursively from completion block which increases the memory foot print, this most probably is leading to a block retain cycle,following is the code:
- (void)tick {
if (counter > counterLimit) {
[self finish];
return;
}
counter++;
context = [[Context alloc] init];
//this is executed in another thread
[self.executer computeWithContext:(Context*)context completion:^(NSDictionary *dictionary, Context *context_)
{
[self handleResponse];
[self tick];
}];
}
self is owning executer, executer is owning the block, the block captures self strongly (same effect as owning). you have a retain cycle.
create a weak reference for self and use that in the block exclusively.
- (void)tick {
// ...
__weak typeof(self) weakSelf = self;
[self.executer computeWithContext:(Context*)context completion:^(NSDictionary *dictionary, Context *context_)
{
typeof(weakSelf) strongSelf = weakSelf;
if(strongSelf) { // ensure the receiver is still there to receive
[strongSelf handleResponse];
[strongSelf tick];
}
}];
}

Retaining self with nested blocks?

With the following code:
#interface MyClass()
{
NSMutableArray * dataArray;
}
#end
#implementation MyClass
- (void) doSomething
{
__typeof__(self) __weak wself = self;
dispatch_async(dispatch_get_global_queue(0,0), ^{
__typeof__(self) sself = wself;
[sself->dataArray addObject: #"Hello World"];
dispatch_async(dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval: 30];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: sself->dataArray[0]
message: #"Message"
delegate: nil
cancelButtonTitle: #"OK"
otherButtonTitles: nil];
[alert show];
});
});
}
#end
Is this the proper way to access sself from within the main queue block?
Would sself go out of scope once the initial queue finished?
Should I add a second __typeof__(self) sself = wself; inside the main queue block?
Yes, sure it is.
No, you'll be able to use in main_queue block.
No, you don't have to. You don't have to add __typeof__(self) sself = wself; even in global_queue block; it's not necessary, you already have a weakened self object wself (moreover, you will retain self in __typeof__(self) part inside the block).
You don't have to use __typeof__. Use simply typeof(self)
You ask:
Is this the proper way to access sself from within the main queue block?
Almost. You also should be checking to make sure sself is not nil, too. You do this because dereferencing a ivar for an nil pointer may crash your app. Thus, check to make sure it's not nil:
- (void) doSomething
{
typeof(self) __weak wself = self;
dispatch_async(dispatch_get_global_queue(0,0), ^{
typeof(self) sself = wself;
if (sself) {
[sself->dataArray addObject: #"Hello World"];
dispatch_async(dispatch_get_main_queue(), ^{
[NSThread sleepForTimeInterval: 30];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle: sself->dataArray[0]
message: #"Message"
delegate: nil
cancelButtonTitle: #"OK"
otherButtonTitles: nil];
[alert show];
});
}
});
}
You then ask:
Would sself go out of scope once the initial queue finished?
It goes out of scope, but is retained by the inner block and will be retained until that inner block finishes.
Should I add a second __typeof__(self) sself = wself; inside the main queue block?
You can if you want to, but it's not necessary. It depends upon the desired behavior. If, for example, you want to see this alert even if the current object (presumably a view controller) is dismissed, then use sself pattern (because you presumably want to hang on to it so you have access to dataArray). If you don't want to show the alert anymore, then you'd repeat this weakSelf/strongSelf dance.

Activity indicator not animating when creating a dispatch group in iOS

I want to display an activity indicator while performing some network calls in a dispatch_group_asyc block. But activity indicator only shows when the block finishes. I'm creating a dispatch_group_t because I need to get the result of the network calls before performing some other tasks. This is a simplified version of my code:
- (BOOL)doNetCall
{
[activityIndicator startAnimating];
__block BOOL netResult = NO;
dispatch_queue_t queue = dispatch_queue_create(netQueue, NULL);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group,queue,^{
netResult = [service queryService];
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
dispatch_release(group);
dispatch_release(queue);
[activityIndicator stopAnimating];
if (netResult) {
// Perform some tasks
}
else {
[self showAlertView];
}
return netResult;
}
What am I doing wrong? Thanks!
EDIT: I need the method to wait until the block finishes in order to return the result I get
You should use activity indicator in this way:
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
// Do something...
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
});
});
If you're using group, just rewrite your code a little bit.
There doesn't appear to be any need for a dispatch group with what you are doing. Try this:
- (void)buttonClicked {
[activityIndicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
BOOL netResult = [service queryService];
dispatch_async(dispatch_get_main_queue(), ^{
[activityIndicator stopAnimating];
if (netResult) {
// perform some tasks
} else {
// show alert
}
});
});
}
If you have your queue, replace the call to dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) with your own queue.

Resources