without ARC, does dispatch_block_cancel release the dispatch block or it need be manually released?
dispatch_block_t work = dispatch_block_create(0, ^{
//...
});
dispatch_block_cancel(work); // Is work released here?
Block_release(work); // Or it need to be released?
Assuming dispatch_block_cancel releases the block, what would be the difference between those two cases?
// Case 1
dispatch_block_t work = dispatch_block_create(0, ^{
//...
});
dispatch_block_cancel(work);
// Case 2
dispatch_block_t work = dispatch_block_create(0, ^{
//...
});
Block_release(work);
Cancelation has no impact on memory management. You called dispatch_block_create, which includes the word "create." That means you are responsible for releasing the memory. Nothing will do it for you.
Related
I wanna to update table from a background thread using this part of the code
__block typeof(self.tableB) self_tableB = self.tableB;
[lwc setBaseControllerCallback:^(int ndx) {
__block typeof(ndx) ndx_t = ndx;
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self_tableB setNumberOfRows: 0 withRowType:TABLEELEMENT];
[self_tableB setNumberOfRows: ndx_t withRowType:TABLEELEMENT];
}];
}];
where
^(int ndx) {
//...
}
is a block called from background thread (NSThread) and lwc - is an instance of my custom background thread class.
To clear this method is called like with:
//code inside thread
if (handlerBase_inner) {
handlerBase_inner(ndx++);
}
So, at
[self_tableB setNumberOfRows: ndx_t withRowType:TABLEELEMENT];
I can see EXC_BAD_ACCESS. Why? What is the
I worry about self_tableB. I'm not sure that you want a strong reference to it, artificially keeping it alive might cause it to have a dangling pointer back to its delegate.
__block __weak typeof(self.tableB) self_tableB = self.tableB;
Adding a weak annotation might to the trick.
- (NSHashTable *)pollers
{
if (!_pollers) {
dispatch_sync(self.serialQueue, ^{
_pollers = [NSHashTable weakObjectsHashTable];
});
}
return _pollers;
}
pollers is a nonatomic property on a singleton. There are some other methods in the singleton where objects are added to pollers, and I'm using #synchronized for their addition ([self.pollers addObject:____]).
Anyway... I have a question about the code above. If 2 threads simultaneously call this function, they could both get past the if (!_pollers) code, and then both will dispatch the _pollers = [NSHashTable weakObjectsHashTable]; code synchronously on our custom serialQueue. So we'll actually run the code twice.
Is there a better way to do this?
You only need a single dispatch_once function for this
Your serial queue is now redundant, as dispatch_once will ensure that the block is only called once (even if invoked at the same time from multiple threads), contrary to what pds says.
The documentation clearly states that:
If [dispatch_once is] called simultaneously from multiple threads, this function waits synchronously until the block has completed.
Your if statement is also redundant, as pointed out by Josh.
Therefore you just want:
- (NSHashTable *)pollers
{
static dispatch_once_t t;
dispatch_once(&t, ^{
_pollers = [NSHashTable weakObjectsHashTable];
});
return _pollers;
}
It's also worth noting that you'll need a thread safe implementation of your singleton's sharedInstance in order for this to be bulletproof. You can do this in much the same way with a dispatch_once. For example:
static singleton* sharedInstance;
+(instancetype) sharedInstance {
static dispatch_once_t t;
dispatch_once(&t, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
Use dispatch_once like this
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
dispatch_sync(self.serialQueue, ^{
_pollers = [NSHashTable weakObjectsHashTable];
});
});
return pollers;
I've been trying to fix this crash for almost a week. The application crashes without any exception or stack-trace. The application does not crash in any way while running through instruments in zombie mode.
I have a method that gets called on a different thread.
The solution that fixed the crash was replacing
[self.mutableArray removeAllObjects];
with
dispatch_async(dispatch_get_main_queue(), ^{
[self.searchResult removeAllObjects];
});
I thought it might be a timing issue, so I tried to synchronize it, but it still crashed:
#synchronized(self)
{
[self.searchResult removeAllObjects];
}
Here is the code
- (void)populateItems
{
// Cancel if already exists
[self.searchThread cancel];
self.searchThread = [[NSThread alloc] initWithTarget:self
selector:#selector(populateItemsinBackground)
object:nil];
[self.searchThread start];
}
- (void)populateItemsinBackground
{
#autoreleasepool
{
if ([[NSThread currentThread] isCancelled])
[NSThread exit];
[self.mutableArray removeAllObjects];
// Populate data here into mutable array
for (loop here)
{
if ([[NSThread currentThread] isCancelled])
[NSThread exit];
// Add items to mutableArray
}
}
}
Is this problem with NSMutableArray not being thread-safe?
No.
It is not thread safe and if you need to modify your mutable array from another thread you should use NSLock to ensure everything goes as planned:
NSLock *arrayLock = [[NSLock alloc] init];
[...]
[arrayLock lock]; // NSMutableArray isn't thread-safe
[myMutableArray addObject:#"something"];
[myMutableArray removeObjectAtIndex:5];
[arrayLock unlock];
As others already said, NSMutableArray is not thread safe. In case anyone want to achieve more than removeAllObject in a thread-safe environment, I will give another solution using GCD besides the one using lock. What you have to do is to synchronize the read/update(replace/remove) actions.
First get the global concurrent queue:
dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
For read:
- (id)objectAtIndex:(NSUInteger)index {
__block id obj;
dispatch_sync(self.concurrent_queue, ^{
obj = [self.searchResult objectAtIndex:index];
});
return obj;
}
For insert:
- (void)insertObject:(id)obj atIndex:(NSUInteger)index {
dispatch_barrier_async(self.concurrent_queue, ^{
[self.searchResult insertObject:obj atIndex:index];
});
}
From Apple Doc about dispatch_barrier_async:
When the barrier block reaches the front of a private concurrent queue, it is not executed immediately. Instead, the queue waits until its currently executing blocks finish executing. At that point, the barrier block executes by itself. Any blocks submitted after the barrier block are not executed until the barrier block completes.
Similar for remove:
- (void)removeObjectAtIndex:(NSUInteger)index {
dispatch_barrier_async(self.concurrent_queue, ^{
[self.searchResult removeObjectAtIndex:index];
});
}
EDIT: Actually I found another simpler way today to synchronize access to a resource by using a serial queue provided by GCD.
From Apple Doc Concurrency Programming Guide > Dispatch Queues:
Serial queues are useful when you want your tasks to execute in a specific order. A serial queue executes only one task at a time and always pulls tasks from the head of the queue. You might use a serial queue instead of a lock to protect a shared resource or mutable data structure. Unlike a lock, a serial queue ensures that tasks are executed in a predictable order. And as long as you submit your tasks to a serial queue asynchronously, the queue can never deadlock.
Create your serial queue:
dispatch_queue_t myQueue = dispatch_queue_create("com.example.MyQueue", NULL);
Dispatch tasks async to the serial queue:
dispatch_async(myQueue, ^{
obj = [self.searchResult objectAtIndex:index];
});
dispatch_async(myQueue, ^{
[self.searchResult removeObjectAtIndex:index];
});
Hope it helps!
As well as NSLock can also use #synchronized(condition-object) you just have to make sure every access of the array is wrapped in a #synchronized with the same object acting as the condition-object , if you only want to modify the contents of the same array instance then you can use the array itself as the condition-object, other wise you will have to use something else you know will not go away, the parent object, i.e self, is a good choice because it will always be the same one for the same array.
atomic in #property attributes will only make setting the array thread safe not modifying the contents, i.e. self.mutableArray = ... is thread safe but [self.mutableArray removeObject:] is not.
__weak typeof(self)weakSelf = self;
#synchronized (weakSelf.mutableArray) {
[weakSelf.mutableArray removeAllObjects];
}
Since serial queues were mentioned: With a mutable array, just asking "is it thread safe" isn't enough. For example, making sure that removeAllObjects doesn't crash is all good and fine, but if another thread tries to process the array at the same time, it will either process the array before or after all elements are removed, and you really have to think what the behaviour should be.
Creating one class + object that is responsible for this array, creating a serial queue for it, and doing all operations through the class on that serial queue is the easiest way to get things right without making your brain hurt through synchronisation problems.
All the NSMutablexxx classes are not thread-safe. Operations including get,insert,remove,add and replace should be used with NSLock.This is a list of thread-safe and thread-unsafe classes given by apple: Thread Safety Summary
Almost NSMutable classes object is not thread safe.
There is a similar question here, which doesn't explain exactly what I want: Objective C Blocks as Async-callbacks & BAD ACCESS
I have a view controller, which calls a service with an async callback. The callback is done using a block, which references variables on the view controller to populate them.
It looks like so:
- (void) loadData {
__block MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
me.data = result;
}
}];
}
However, if I dealloc the view controller, 'me' is then badly accessed by the callback.
What is the simplest way of making 'me' NULL? If i put it as an iVar, it then brings back the circular reference... i think?
I think I'm missing something obvious....
Thanks
Are you targeting iOS 5.0 or later (or Mac OS X 10.7 or later)? If so, you can use ARC and a __weak variable (instead of a __block one). This will automatically zero out when the referenced object is deallocated. Your code would look like
- (void)loadData {
__weak MyViewController *me = self;
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
if (!error) {
MyViewController *strongMe = me; // load __weak var into strong
if (strongMe) {
strongMe.data = result;
}
}
}];
}
If you need support for an older OS then you need to find a different solution. One solution is to just go ahead and let the block retain self. If the service is guaranteed to execute the completion block (and then release it), this will only produce a temporary cycle that will break automatically when the completion block is run. Alternatively if you have some way to cancel the service (in a way that guarantees the block cannot be called after the cancellation), you can stick with the __block and just be sure to cancel the service in your -dealloc. There's other alternatives too but they're more complicated.
I did a combination of things above from the suggestions. Including nilling the blocks. Although, my objects are still not getting released immediately. i.e. I'd put a breakpoint on dealloc of MyViewController, and without the __block variable it would get called at a much later point in time (probably due to the async connection) and sometimes not at all.
The code is fairly complex - so I imagine there are other things going on for it to not work as suggested above.
What I have also done, is used Mike Ash's MAZeroingWeakRef, which i guess is the same as using __weak - which #KevinBallard suggested.
Below is how I've implemented it, and it appears to be working. Dealloc is called immediately on disposal of the view controller, which i want. And I can't get it to crash... and with the log comment that i've put in, I can already see that I'm dodging bullets.
- (void) loadData {
__block MAZeroingWeakRef *zeroWeakRef = [[MAZeroingWeakRef alloc] initWithTarget:self];
[zeroWeakRef setCleanupBlock: ^(id target) {
[zeroWeakRef autorelease];
}];
[self.service executeWithCompletion:^(NSArray *result, NSError *error) {
MyViewController *me = [zeroWeakRef target];
if (!me) {
DULog(#"dodged a bullet");
}
if (!error) {
me.data = result;
}
}];
}
Is there a real retain cycle problem that you're trying to avoid? Is there a reason that self should not simply be retained until -executeWithCompletion: completes? Is there any real chance that it won't complete?
So long as it really will eventually complete (even with failure) and so long as it releases the block after invoking it (perhaps by setting a property to nil), then the retain cycle will eventually be broken and all will be well.
I've had a look around but have been unable to find a definitive answer to this question.
If I have a class that performs an async operation, when and how do I release it?
-(void)main
{
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
When do I release *async?
You could keep a private property to save the value, or, if you have control over the AsyncObject, pass the instance in the didSomething: selector.
I think the first option is better since you know the object will be retained until you get your delegate call.
Option 1:
ClassName.m
#interface ClassName ()
#property (nonatomic, retain) AsyncObject* async;
#end
#interface
//...
-(void)main
{
async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
[async release];
async = nil;
}
Option 2:
-(void)aysncObject:(AsyncObject*)async didSomething:(Result*)result {
[async release];
}
If your object runs its asynchronous task on a background thread, or is the target of a timer, or uses GCD and is referenced within the scope of the dispatched block (the ^ {} kerjigger) then it will be retained for you for the lifetime of that background operation.
So the normal use case would be:
AsyncObject *async = [[AsyncObject alloc] initWithDelegate:self];
[async goDoSomething];
[async release];
Now, it's possible to work in the background with an object that is not retained (e.g. by using a __block-scoped reference to the object with GCD, or by detaching your worker thread with pthreads instead of NSThread/NSOperation) but there are no typical use cases I can think of offhand where that would happen. In such a case, you should ensure that -goDoSomething internally retains and releases self for the duration of the operation.
(If somebody can think of a case where the object is not retained for you, please post in the comments and I'll update my answer.)
Thanks for the help guys, I did a bit of experimenting with NSURLConnection to see how it handled it (As you autorelease that and it will continue on with it's async operations).
Turns out at the beginning of every async step it internally bumps its retain count and at the end of every async step it internally releases itself.
This means that it can be sent autorelease/release and it won't actually be release until it has completed it's current operation.
// MAIN.M
-(void)main
{
AsyncObject *async = [[[AsyncObject alloc] initWithDelegate:self] autorelease];
[async goDoSomething];
}
-(void)didSomething:(Result*)result
{
}
// ASYNCOBJECT.M
-(void) goDoSomething
{
[self retain];
}
-(void) finishedDoingSomething
{
[delegate didSomething:result];
[self release]
}