I have an IOS project (ARC disabled) which has several view controllers. One particular controller initialises a member object of type MyClass, however when the view controller is dismissed, I'm calling a cleanup method for the object which uses a thread (using dispatch-async) to make some time consuming operations and then when these operations are done im executing a [self release] on the main queue for the object. Is this a good practise, will it cause any errors? Below is a similar example to what im doing:
#implementation ViewController
- (void)viewDidLoad
{
myObj = [[MyClass alloc] init];
}
-(void)viewWillDisappear
{
[myObj cleanup];
}
#end
//myClass
#implementation MyClass
- (void)cleanup()
{
dispatch_queue_t myQueue = dispatch_queue_create ("MyClassDeallocQueue", NULL);
dispatch_async(myQueue, ^{
//time consuming operations
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
}
#end
Is this a good practise, will it cause any errors?
Currently, your code has an unbalanced retain/release. That is definitely an error (over release).
"Is it good practice?" - well, I don't know what you are trying to accomplish. But if your goal is to keep self alive, until after the block is executed, it is already accomplished purely through the fact that self will be captured. So, strictly a release is not needed.
However, if you NOT explicitly release self on the main thread, you introduce a subtle bug: it might happen that the block has the last reference to self, and since it may execute on some arbitrary thread, it will release self on this non-main thread. And this is forbidden: UIKit methods (including dealloc) MUST be called on the main thread!
Thus, it might make sense:
[self retain];
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self release];
});
});
or shorter:
dispatch_async(myQueue, ^{
// time consuming operation, which captures `self`
[self doSomething];
...
// ensure that `dealloc` will be executed on the main thread, if
// last reference is held by the block:
dispatch_async(dispatch_get_main_queue(), ^{
[self self];
});
});
Edit:
It's an interesting question, whether the "short" version is actually tread-safe or has a race:
Suppose, self will be released in the block executed on myQueue, as the effect of capturing self before it will be retained in the same bock as an effect of capturing self for the block executed on the main queue. Then, we have an issue. Comments appreciated.
Related
In a class, I've declared a thread like:
#property (nonatomic, strong) dispatch_queue_t databaseQueue;
and then I perform an operation this thread like
dispatch_async(self.databaseQueue, ^{
[self.dao deleteRetries];
});
Can this potentially create a retain cycle?
AND
the current class holds a strong reference to viewControllerToDismiss and there is a code which looks like:
[viewControllerToDismiss dismissViewControllerAnimated:shouldAnimateDismiss completion:^{
[self performSomeAction];
}
is this a retain cycle?
It is merely a strong reference to self that is eliminated automatically when the block finishes running and GCD releases the block. Note, this is a strong reference between the queue object itself, the block, and self, but not to databaseQueue. E.g. even if databaseQueue was some local reference that had fallen out of scope after you dispatched but before it ran, you'd still have a strong reference between the queue object, the block, and self.
If you don't want that strong reference at all, use weakSelf pattern:
typeof(self) __weak weakSelf = self;
dispatch_async(self.databaseQueue, ^{
[weakSelf.dao deleteRetries];
});
You asked:
Please could you elaborate more on "Note, this is a strong reference between the queue object itself, the block, and self, but not to databaseQueue"?
Consider:
- (void)runManyTasks {
dispatch_queue_t queue = dispatch_queue_create("com.domain.app.foo", 0);
for (NSInteger i = 0; i < 10; i++) {
dispatch_async(queue, ^{
[self doSomething];
});
}
}
- (void)doSomething {
[NSThread sleepForTimeInterval:1];
}
Even though I have no references in my code to that local variable, queue, after runManyTasks finishes, if I call runManyTasks, GCD will keep its own strong reference to the actual underlying queue object until all tasks finish, and the queue will keep copies of those blocks until they finish running, and those blocks will maintain a strong reference to self until GCD finishes with all of them (roughly 10 seconds, in this example).
You go on to edit your question and ask:
the current class holds a strong reference to viewControllerToDismiss and there is a code which looks like:
[viewControllerToDismiss dismissViewControllerAnimated:shouldAnimateDismiss completion:^{
[self performSomeAction];
}
is this a retain cycle?
For all practical considerations, no. That block is released as soon as the dismissal animation is done, so you generally wouldn't complicate your code with weakSelf pattern here. In fact, that view controller isn't dismissed until the animation finishes, anyway, so there's absolutely nothing gained from weakSelf pattern (other than making code more convoluted).
First, you have not declared a thread. It’s a queue, that’s something different. (Fortunately, as working directly with threads is a pain.)
You are dispatching a block into the queue. The block retains self and the queue retains the block, which means you do have a retain cycle, since the queue, being a strong property, is retained by self:
self -> queue -> block -> self -> queue -> …
BUT the block should be short-lived, judging by the API. When the block is finished, it will get released from the queue, breaking the retain cycle. So I would not worry about a case like this.
Using self directly in blocks will create strong retain cycle.
To avoid retain cycle, please check below code
__weak YourViewController *weakSelf = self;
dispatch_async(self.databaseQueue, ^{
if (weakSelf){
YourViewController *strongSelf = weakSelf;
[strongSelf.dao deleteRetries];
}
});
For more info visit this link Working with blocks
I am a newbie. I am using Grand Central Dispatch to populate an array (student_temp) on another thread. That part is working fine. The problem is I cannot pass the array to a class property (student_Array) where it is used throughout the class. I can't get the array back on the main thread.
it works fine until I get back tot he main thread and I can't pass student_temp into student_Array (the property) either inside or outside of GCD.
What am I doing wrong, or is there a better to populate the array property using GCD?
Thank you for your help. And please try to explain in non-technical language if possible I am new at this.
- (void)viewDidLoad
{
[super viewDidLoad];
R2LFetcher *studentFetch = [[R2LFetcher alloc] init];
__block NSMutableArray *student_temp = [[NSMutableArray alloc] init];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
//long-running code goes here…
student_temp = [studentFetch fetchToStudentArray];
dispatch_async(dispatch_get_main_queue(), ^{
// code the updates the main thread (UI) here...
student_Array = student_temp;
});
});
student_Array = student_temp;
A couple of reactions:
In the last line of your code, you're setting student_Array to student_temp. Clearly that line makes no sense because you're populating student_temp asynchronously. And you're opening yourself up to synchronization issues if you're trying to simultaneously access the save variable in two queues. Don't bother to assign student_Array to student_temp at the end of viewDidLoad, but rather just do it inside the nested dispatch_async calls.
Inside the block, you're populating and setting student_temp. It probably makes more sense to make that variable scoped within that block, avoiding temptation to access it from outside that block as well as simplifying your code because the __block qualifier is no longer needed.
This block is running asynchronously, so when you update student_Array in the main queue, you might want to update your UI at the same time (e.g. reload the tableview or whatever). Perhaps you're doing that already and just removed it for the sake of brevity, but I just wanted to make sure.
Thus:
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
R2LFetcher *studentFetch = [[R2LFetcher alloc] init];
// long-running code goes here, for example ...
NSMutableArray *student_temp = [studentFetch fetchToStudentArray];
dispatch_async(dispatch_get_main_queue(), ^{
student_Array = student_temp;
// code the updates the main thread (UI) here, for example...
[self.tableView reloadData];
});
});
}
You should be able to add objects to student_Array directly from your block. Unlike stack variables, properties and ivars don't get copied when used inside a block. Instead, self gets retained in the block, and the property is referenced through it.
Of course, you need to be aware of concurrency issues, e.g. if you need to access the data from the main thread as well. For that, you probably still want to have this at the end of your async GCD block:
// done populating the data
dispatch_async(dispatch_get_main_queue(), ^{
// update the UI
}
I have a game written using the new SpriteKit in iOS7. I have a customised SKSpriteNode which would fetch and display a Facebook profile picture. However, since it may take some time to load the picture. I tried to load the picture in background when I initialised the node and display it only when the picture is loaded. Here is code snippet I wrote:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Code to load Facebook Profile picture
// ...
SKSpriteNode *fbFrame = [SKSpriteNode spriteNodeWithTexture:facebookPicTexture];
dispatch_async(dispatch_get_main_queue(), ^{
// self is my customised SKSpriteNode - so here I just add a sprite node of
// a facebook picture to myself as a child
[self addChild:fbFrame];
});
});
It works fine normally. However, if the loading of Facebook profile pic is slow, the user may have already switch to another screen when the picture is loaded. In such case, self will actually be removed from the scene hierarchy and no reference will be made to it.
When I read the block doc, I think the async block will retain self and so I presume it will still be valid when the main thread block is called. It turns out from time to time if the pic loading is really slow and the second dispatch_async is called when self is removed from the hierarchy, a bad access error will occur at the line [self addChild:fbFrame].
Am I understand the block memory management incorrectly? And is there a way to solve that kind of problem?
Your understanding of the memory management is correct, that the presence of self in this block will retain self until the dispatched block is completed. The solution is to not retain self while the block runs, by using a weak reference to self inside the block:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do some stuff in background here; when done, then:
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf addChild:fbFrame];
});
});
You should review that block for any references to self (either explicit or implicitly by referencing an ivar directly), and replace them with weakSelf.
Or, (unlikely in this case) sometimes you'll see the weakSelf/strongSelf pattern where you must ensure that self isn't released during the execution of that nested block:
__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// do some stuff in background here; when done, then:
dispatch_async(dispatch_get_main_queue(), ^{
typeof(self) strongSelf = weakSelf;
if (strongSelf) {
// stuff that requires that if `self` existed at the start of this block,
// that it won't be released during this block
}
});
});
By the way, the other approach is to cancel the network request when the view controller is dismissed. This requires a more significant change (using a NSOperation-based approach rather than GCD; or use NSURLSessionTask-based approach that allows you to cancel the request), but it is the other way to tackle this.
I think you need to write like this:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
objc_setAssociatedObject(self, #"yourTag", #"Alive", OBJC_ASSOCIATION_RETAIN);
dispatch_async(queue, ^{
// Code to load Facebook Profile picture
// ...
SKSpriteNode *fbFrame = [SKSpriteNode spriteNodeWithTexture:facebookPicTexture];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *strAlive = (NSString *)objc_getAssociatedObject(self, #"yourTag");
if (strAlive)
{
// self is my customised SKSpriteNode - so here I just add a sprite node of
// a facebook picture to myself as a child
[self addChild:fbFrame];
}
});
});
dispatch_release(queue);
When you dont want the dispatch to continue procedure when the self (ViewController) is not visible anymore so write this:
objc_setAssociatedObject(self, #"yourTag", nil, OBJC_ASSOCIATION_RETAIN);
In:
- viewWillDisapear Or - viewDidDisapear
And renew calling the dispatch when you come back to than screen.
I'm trying to figure out if I do this right:
If I have one block, I'll do this:
__weak MyClass *weakSelf = self;
[self performBlock:^{ //<< Should I use self, or weakSelf here?
[weakSelf doSomething];
} afterDelay:delay];
But what happens if there's a block in a block? Would this be correct?
__weak MyClass *weakSelf = self;
[self performBlock:^{
[weakSelf doSomething];
[self performBlock:^{
[weakSelf doSomething];
} afterDelay:1.0f];
} afterDelay:delay];
Also, in the function below, do I need to use [block copy]?
- (void)performBlock:(void (^)(void))block afterDelay:(float)delay
{
if (block)
{
if (delay > 0)
{
[self performSelector:#selector(executeBlockAfterDelay:) withObject:[block copy] afterDelay:delay];
}
else
{
[self executeBlockAfterDelay:[block copy]];
}
}
}
- (void)executeBlockAfterDelay:(void(^)(void))block
{
if (block)
block();
}
In this case (below) use just strong self, because the block is copied just for those few seconds. And usually if you want the self to perform block, you want to it to stay alive until that time, so strong reference is perfectly okay.
[self performBlock:^{
[self doSomething]; // strong is OK
} afterDelay:delay];
Block inside a block? In your case those two block are just delayed one-shot blocks, so the same as above, use strong. But there are differences between blocks. If you store the block for longer time, maybe for multiple invocations you should avoid retain-cycles.
Example:
self.callback = ^{
[self doSomething]; // should use weakSelf
};
This may cause retain-cycle. In fact it depends on how the block is used. We see that the block is stored (copied) in property for later use. However, you can prevent the retain-cycles by nullifying block that will not be used any more. In this case:
self.callback(); //invoke
self.callback = nil; //release
When using ARC, you don't have to copy blocks yourself. There were bugs in early versions after blocks were added, but now the compiler under ARC knows when to copy blocks. It is clever enough to copy it in this case:
[self performSelector:#selector(executeBlockAfterDelay:) withObject:block afterDelay:delay];
Rather than implementing -performBlock:afterDelay:, just use dipatch_after(). Among other things, that's not a message delivered to an object, so there's no question of what receiver to target it at.
Actually, there's no memory management issue here at all. One typically only needs to do a "weak self" approach when an object retains a block and the block (perhaps implicitly) retains that same object. However, the object is not retaining the block. It is being retained by the framework until the -performSelector:withObject:afterDelay: fires, but that's not a retain cycle.
If there were a retain cycle, then you should not reference self in the blocks. So, your nested case is wrong in invoking a message on self rather than weakSelf.
Finally, yes, you do need [block copy] whenever you are keeping a block after execution leaves the scope of its declaration or if you pass it to non-block-specific API that does. That is, you don't need to copy a block when you pass it to, say, dispatch_async() because that's a block-aware API that knows to make its own copy as necessary. But -performSelector:withObject:afterDelay: is not block-aware. It just treats its argument as a generic object and retains it. So, you do have to copy the block when passing it to that.
One the most important thing to understand about blocks is that they capture a piece of code (including values) in an abstract entity that can be manipulated as an atomic object (keep it somewhere, pass it, copy, etc...). Actually it is implemented in a way that guarantee that by default your block will remain valid and executable safely later.
Then capturing and retaining the required dependencies inside the block is necessary.
Unfortunately, in some cases (quite often actually) the block is retained by the instance that creates it and it retains itself that instance. This is called a retain loop and makes your object and your block impossible to dealloc unless you break one of the retaining relation yourself. This can happen if you reference your block with an instance variable for example and you don't nillify it manually.
This is probably the main issue with blocks especially because sometime, you don't know that your block retains your self instance (NSAssert within your block for example). Then:
If you execute your block immediately and release it (use your block
with dispatch release it after execution) there is no risk since you
are sure your object referenced by self still exist.
But if the execution is delayed it is important to retain your object within your block. But in that case your object should not retain your block to avoid a retain loop (A retains B and B retains A). If you define and optionally reference your block in the private scope of method it is perfect.
About copy. Yes it can be safer to use copy if your block in passed as a method argument to be sure you have a clean exclusive block in this scope with a +1 retainCount. But maybe ARC already do it for you. Not sure about that. For example it performWithSelector seems to do it for free, then copy is not dangerous. Just a useless. Sometime the compiler can optimise that by removing it but it has to be checked.
I usually do this:
__unsafe_unretained __block id blockSelf = self;
and then use it in my blocks no issues.
So in your case:
__unsafe_unretained __block MyClass *blockSelf = self;
[self performBlock:^{
[weakSelf doSomething];
[self performBlock:^{
[weakSelf doSomething];
} afterDelay:1.0f];
} afterDelay:delay];
Also to make your life a tad easier - make a utilities class and put this in the header
void RunAfterDelay(NSTimeInterval delayInSeconds, dispatch_block_t block);
and then this in the .m file
void RunAfterDelay(NSTimeInterval delayInSeconds, dispatch_block_t block)
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
Import the utilities into your prefix and you can go:
__unsafe_unretained __block MyClass *blockSelf = self;
RunAfterDelay(1.0f,^{
[blockSelf doSomething];
RunAfterDelay(delay,^{
[blockSelf doSomething];
})
});
I find it a bit nicer to read than the verbose default ones.
Hope this helps :)
I am using background operations heavily and I was just curious if this would ever cause a deadlock. I have a Core Data Managed Object Context set to use a private queue that is referenced (possibly simultaneously) from a few different threads using performblockandwait. Under certain conditions a background task may be kicked off via the completion of another background task.
Something like the following is a possibility since my background tasks are started when certain conditions are met, which could occur from user input on the main thread or a background task.
- (void)task1
{
__weak MyClass *weakself = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0),^{
....
....
[context performBlockAndWait:^{
BOOL condition = [weakself performDbCleanup];
if (condition)
{
[weakself task2];
}
}];
});
}
- (void)task2
{
__weak MyClass *weakself = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0),^{
....
....
[context performBlockAndWait:^{
[weakself performDbCleanup2];
}];
});
}
Its hard to explain exactly why I need to do things this way, but I do need performBlockAndWait in both instances because this is a highly simplified version of what is happening. Long processing happens before and after the performBlockAndWait calls that I don't want blocking access to the DB Context, and also should not be blocking the main thread.