Call Block_Release inside block to be released - objective-c

Is it possible to release a block inside itself? For the compiler it's fine, but I'm not sure if at runtime it will crash, since it releases memory that is executed at the same time.
cancel_block_t someFunction(/*args*/){
__block BOOL canceled = NO;
__block cancel_block_t cancel_block = Block_copy(^{
canceled = YES;
Block_Release(cancel_block); //<-- can I do this?
cancel_block = NULL; //<-- can I do this?
});
// […]
return cancel_block;
}
Would this approach be more safe?
cancel_block_t someFunction(/*args*/){
__block BOOL canceled = NO;
__block cancel_block_t cancel_block = Block_copy(^{
canceled = YES;
dispatch_async(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),^{
Block_Release(cancel_block);
cancel_block = NULL;
});
});
// […]
return cancel_block;
}
Thanks for help!
Edit #1: corrected return type of function.

Is this non-ARC code? ARC will automatically copy, retain, and release blocks.
Anyway, this is not safe, at least not always. I've seen crashes for similar behavior. The issue is that the reference to the __block variable is within the same block object that Block_release() may deallocate. So, trying to set the variable can access memory after it's been freed (and maybe reused).
About your function:
1) Why does it return a pointer to a block type? It would be more normal for the function to just return the block type (which is already a reference). That is, someFunction() should have a return type of cancel_block_t, not cancel_block_t*. Anyway, it's not safe to take the address of a __block variable, since such a variable can change location. It starts life on the stack but gets moved to the heap.
2) The normal semantics for a function that returns a block would be to return an autoreleased object. So, someFunction() should just return [cancel_block autorelease]; (given that it's already been copied). The caller is responsible for retaining it if it wants to keep it beyond the current scope or autorelease pool. If it's submitted to a function (e.g. dispatch_async()), then that function is responsible for retaining it. In other words, the memory management semantics are the same as any other object. The block should not try to release itself.

Related

Why need to copy the objective-c handler before cast it to void* type?

I want to simulate the NSAlert member function which only exist on 10.9.
- (void)beginSheetModalForWindow:(NSWindow *)sheetWindow completionHandler:(void (^)(NSModalResponse returnCode))handler NS_AVAILABLE_MAC(10_9);
The code is as following:
-(void)compatibleBeginSheetModalForWindow: (NSWindow *)sheetWindow
completionHandler: (void (^)(NSInteger returnCode))handler
{
void *handlerValue = (__bridge void*) [handler copy];
[self beginSheetModalForWindow: sheetWindow
modalDelegate: self
didEndSelector: #selector(blockBasedAlertDidEnd:returnCode:contextInfo:)
contextInfo: handlerValue];
}
-(void)blockBasedAlertDidEnd: (NSAlert *)alert
returnCode: (NSInteger)returnCode
contextInfo: (void *)contextInfo
{
void(^handler)(NSInteger) = (__bridge typeof(handler)) contextInfo;
handler(returnCode);
[handler release];
}
I need to copy the handler before cast it to void*, else it will crash, if I change it to following line:
void *handlerValue = (__bridge void*) handler;
And by check the handler in blockBasedAlertDidEnd:returnCode:contextInfo:, it is an incorrect value.
Even I call [handler retain] before cast to void* it doesn't work.
It is quite confuse to me, so why I need to copy it?
This is because blocks are created on the stack and not the heap. So when the stack pointer moves on the memory in that stack frame is returned and the block is lost. Thats why you always should copy blocks and not retain them. When you run copy on a block the new copy is allocated on the heap and therefor don't get removed.
Peter Segerblom covered the basics of it. In the current implementation, there are 3 kinds of blocks. Blocks that don't capture local variables are global blocks; there is just one instance that has static lifetime. Blocks that do capture local variables start out as objects on the stack; and copying it will return a block on the heap. Copying heap or global blocks will simply return the same instance.
Basically, a block passed into your function could be a stack block or not. A stack block is only valid for the current function call. Since it could be a stack block, you must use a copy of it if you want to store it somewhere that outlives the current function call. This is the contract for functions that take a block parameter.
Now, if all your function does with this block is pass it to another function, do you need to pass a copy? If this function parameter is of block type, then no, because if this function needs to keep the block around for later, then it is responsible for copying it (according to the contract above). So you don't need to worry about it. But, if you pass it to a function that is not of block type (e.g. -[NSMutableArray addObject:]), then that function does not know to potentially copy it (it doesn't even know it's a block). In that case, you will have to pass a copy if that function keeps the object around for later. This is the case with the function you are passing to here.

Autoreleasing blocks in NSMutableArray retained by their creator

I'm trying to write a category based on node.js EventEmitter, which can take a number of blocks, store them weakly in an array, and execute them later if the instance creating the block isn't deallocated (in which case they would be removed from the array). This is in order not to keep filling the array with old, unused blocks.
The problem is that the blocks seem to be copied by the class, and thusly never released, even though the instance creating the block is deallocated.
So the implementation looks something like this;
Usage
[object on:#"change" do:^(id slf, NSArray *args) {
NSLog(#"something changed");
}];
Implementation (WeakReference class found here, courtesy of noa)
- (void)on:(NSString *)eventType do:(Callback)callback
{
NSMutableArray *callbacks = self.emitterEvents[eventType];
__weak Callback wcb = callback;
// Wrap the callback in NSValue subclass in order to reference it weakly
WeakReference *cbr = [WeakReference weakReferenceWithObject:wcb];
callbacks[callbacks.count] = cbr;
}
- (void)emit:(NSString *)eventType withArgs:(NSArray *)objArgs
{
NSInteger idx = 0;
NSMutableIndexSet *indices = [NSMutableIndexSet indexSet];
callbacks = (NSMutableArray *)callbacks;
for (WeakReference *cbv in callbacks) {
__weak id cb = [cbv nonretainedObjectValue];
if (cb) {
Callback callback = (Callback)cb;
__weak id slf = self;
callback(slf, objArgs);
} else {
[indices addIndex:idx];
}
idx++;
}
[callbacks removeObjectsAtIndexes:indices];
}
I read something about blocks being copied when used past their scope, but frankly, reading about all these block semantics is kind of making my head spin right now.
Is this way of approaching the problem even possible?
In Objective-C, blocks are objects, but unlike other objects, they are created on the stack. If you want to use the block outside of the scope it was created you must copy it.
[object on:#"change" do:^(id slf, NSArray *args) {
NSLog(#"something changed");
}];
Here, you are passing a pointer to a block on the stack. Once your current stack frame is out of scope, your block is gone. You could either pass a copy to the block, making the caller the owner of the block, or you could copy the block in the receiver.
If you want the caller to own the block, then you have to keep a strong reference to the block in the caller (e.g. as a property). Once the caller gets deallocated, you lose your strong reference and your weak reference is set to nil.
copy a block which is already copied is same as retain it, so if the caller of the method copy the block first then pass it to the method, it should works as you expected. but this means you cannot simply use the method as you described in your usage section.
you have use it like this
typeofblock block = ^(id slf, NSArray *args) {
NSLog(#"something changed");
};
self.block = [block copy]
[object on:#"change" do:self.block];
to actual solve the problem, you have to figure out owns the block. the caller of on:do:, or the object been called?
sounds to me you want to remove the block when the caller is deallocated, which means the owner of the block is the caller. but your on:do: method does not aware the owner of the block, and cannot remove the block when the caller is deallocated.
one way is to pass the owner of the block into the method and remove the block when it deallocated. this can be done use associate object.
- (void)on:(NSString *)eventType do:(Callback)callback sender:(id)sender
{
// add the block to dict
// somehow listen to dealloc of the sender and remove the block when it is called
}
another way is to add new method to remove the block, and call the method in dealloc or other place to remove the block manually.
your approach is similar to KVO, which require the observer to unregister the observation, and I think is a good practice that you should follow.
Thanks for the answers, I realize I was a little bit off on how blocks are managed. I solved it with a different approach, inspired by Mike Ash's implementation of KVO with blocks & automatic dereferencing, and with xlc's advice on doing it in dealloc.
The approach is along the lines of this (in case you don't want to read the whole gist):
Caller object assigns listener to another object with on:event do:block with:caller
Emitter object creates a Listener instance, with a copy of the block, reference to emitter & the event-type
Emitter adds the copied block to an array inside a table (grouped by event-types), creates an associated object on the caller and attaches the listener
Emitter method-swizzles the caller, and adds a block to its dealloc, which removes itself from the emitter
The caller can then choose to handle the listener-instance, which is returned from the emit-method, if it wants to manually stop the listener before becoming deallocated itself
Source here
I don't know if it is safe for use, I've only tested it on a single thread in a dummy-application so far.

Objective-C block "retain cycle" warning, don't understand why

I've seen several other questions of the same form, but I either a) can't understand the provided answers, or b) don't see how those situations are similar to mine.
I'm writing a Category on UIView to recursively evaluate all the subviews of a UIView and return an Array of subviews passing a test. I've noted where my compiler warning occurs:
-(NSArray*)subviewsPassingTest:(BOOL(^)(UIView *view, BOOL *stop))test {
__block BOOL *stop = NO;
NSArray*(^__block evaluateAndRecurse)(UIView*);
evaluateAndRecurse = ^NSArray*(UIView *view) {
NSMutableArray *myPassedChildren = [[NSMutableArray alloc] init];
for (UIView *subview in [view subviews]) {
BOOL passes = test(subview, stop);
if (passes) [myPassedChildren addObject:subview];
if (stop) return myPassedChildren;
[myPassedChildren addObjectsFromArray:evaluateAndRecurse(subview)];
// ^^^^ Compiler warning here ^^^^^
// "Capturing 'evaluateAndRecurse' strongly in this block
// is likely to lead to a retrain cycle"
}
return myPassedChildren;
};
return evaluateAndRecurse(self);
}
Also, I get a bad_access failure when I don't include the __block modifier in my block's declaration (^__block evaluateAndRecurse). If someone could explain why that is, that would be very helpful too. Thanks!
The problem here is that your block evaluteAndRecurse() captures itself, which means that, if it's ever to be copied (I don't believe it will in your case, but in slightly less-trivial cases it may), then it will retain itself and therefore live forever, as there is nothing to break the retain cycle.
Edit: Ramy Al Zuhouri made a good point, using __unsafe_unretained on the only reference to the block is dangerous. As long as the block remains on the stack, this will work, but if the block needs to be copied (e.g. it needs to escape to a parent scope), then the __unsafe_unretained will cause it to be deallocated. The following paragraph has been updated with the recommended approach:
What you probably want to do here is use a separate variable marked with __unsafe_unretained that also contains the block, and capture that separate variable. This will prevent it from retaining itself. You could use __weak, but since you know that the block must be alive if it's being called, there's no need to bother with the (very slight) overhead of a weak reference. This will make your code look like
NSArray*(^__block __unsafe_unretained capturedEvaluteAndRecurse)(UIView*);
NSArray*(^evaluateAndRecurse)(UIView*) = ^NSArray*(UIView *view) {
...
[myPassedChildren addObjectsFromArray:capturedEvaluateAndRecurse(subview)];
};
capturedEvaluateAndRecurse = evaluteAndRecurse;
Alternatively, you could capture a pointer to the block, which will have the same effect but allow you to grab the pointer before the block instantiation instead of after. This is a personal preference. It also allows you to omit the __block:
NSArray*(^evaluateAndRecurse)(UIView*);
NSArray*(^*evaluteAndRecursePtr)(UIView*) = &evaluateAndRecurse;
evaluateAndRecurse = ^NSArray*(UIView*) {
...
[myPassedChildren addObjectsFromArray:(*evaluateAndRecursePtr)(subview)];
};
As for needing the __block, that's a separate issue. If you don't have __block, then the block instance will actually capture the previous value of the variable. Remember, when a block is created, any captured variables that aren't marked with __block are actually stored as a const copy of their state at the point where the block is instantiated. And since the block is created before it's assigned to the variable, that means it's capturing the state of the capturedEvaluteAndRecurse variable before the assignment, which is going to be nil (under ARC; otherwise, it would be garbage memory).
In essence, you can think of a given block instance as actually being an instance of a hidden class that has an ivar for each captured variable. So with your code, the compiler would basically treat it as something like:
// Note: this isn't an accurate portrayal of what actually happens
PrivateBlockSubclass *block = ^NSArray*(UIView *view){ ... };
block->stop = stop;
block->evaluteAndRecurse = evaluateAndRecurse;
evaluteAndRecurse = block;
Hopefully this makes it clear why it captures the previous value of evaluateAndRecurse instead of the current value.
I've done something similar, but in a different way to cut down on time allocating new arrays, and haven't had any problems. You could try adapting your method to look something like this:
- (void)addSubviewsOfKindOfClass:(id)classObject toArray:(NSMutableArray *)array {
if ([self isKindOfClass:classObject]) {
[array addObject:self];
}
NSArray *subviews = [self subviews];
for (NSView *view in subviews) {
[view addSubviewsOfKindOfClass:classObject toArray:array];
}
}

Memory management with block and ARC, leak?

I need to know if I do it correctly. The application is running OK but I'm not sure I get the lifecycle correctly (leak ?).
Note: Instrument see no leak.
The code of a method aaa: of some class A:
- (void) aaa {
NSString *path = ...something...;
NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
// using path
[self somethingElseWith:path];
}];
[self.aQueue addOperation:theOp];
}
So I create a block to put on aQueue (NSOperationQueue*). The goal is to offload from the main thread the long running somethingElseWith: method, so that the GUI continue to be responsive.
Inside the block I reference the local var "path" that will be out of scope at the end of the aaa: method.
If I read the doc correctly, the block will do a retain on 'path'. But is ARC inserting a release at the end of this block implicitly ? Would be logical and nice.
Or should I declare 'path' as __block and assign it to nil at the end of my block ? (manual...)
Not sure I understand how to use __weak in this context.
The path variable is fine. You may however need to avoid a retain cycle by using a weak reference to self. If aQueue is a strong reference there may be a retain cycle causing self never to be released.
Solution:
- (void) aaa {
NSString *path = ...something...;
__weak id self_ = self;
NSBlockOperation* theOp = [NSBlockOperation blockOperationWithBlock: ^{
// using path
[self_ somethingElseWith:path];
}];
[self.aQueue addOperation:theOp];
}
Make sure the operation does not get called after the class should no longer exist.
The block will automatically handle memory management for any locals from the enclosing scope. You don't have to worry about retain/release pairs in this case. Note, though that path will be const within the block's scope. If you need pathto be mutable within the block, use the __block attribute.
The different ways a block handles variables is described in detail here: Blocks and Variables

How can code inside an Objective-C block reference the block object itself?

self is merely a captured variable inside a block and doesn't reference the block itself, so how does a block reference itself without having an explicit captured variable for that purpose?
__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
strawberryFields);
you use the __block because the block will make a copy of the value of strawberryFields when the block is created which will be before the assignment.
you also must copy the block prior to any other copy operation or else you'll end up with a block that references the on-stack original version.
note that the above code leaks the block. Somewhere, there needs to be a release of that block to balance the copy.
I found this pattern to work and stable for ARC (automatic reference counting), both in Debug and Release builds.
-(void) someMethod
{
// declare a __block variable to use inside the block itself for its recursive phase.
void __block (^myBlock_recurse)();
// define the block
void (^myBlock)() = ^{
// ... do stuff ...
myBlock_recurse(); // looks like calling another block, but not really.
};
// kickstart the block
myBlock_recurse = myBlock; // initialize the alias
myBlock(); // starts the block
}
Initially I tried just putting a __block modifier to myBlock and use that variable directly to recurse within the block's implementation. That works on the ARC Debug build but breaks with an EXC_BAD_ACCESS on the Release build. On the other hand removing the __block modifier raises a "variable not defined when captured by block" warning (and I was reluctant to run it and test).
I have never tried this before and not 100% sure it's useful, if valid, but for example:
typedef void (^BasicBlock)(void);
__block BasicBlock testBlock;
testBlock = ^{NSLog(#"Testing %p", &testBlock);};
testBlock();
You probably have declare the variable with __block to prevent self-retain cycle.
The block needs some way to nil out its own reference. Typically it is done by storing the block in a property of the class.
Sometimes you can prefer to not use a property. Here is how you do it without a property:
__weak id weakSelf = self;
__block id block = ^{
if(weakSelf) {
// .. do whatever
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
else {
block = nil;
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
The key thing to keep in mind is that all code paths must lead to a block = nil. We do that here by calling the block every 5 seconds until weakSelf turns nil.
Note that in ARC, it's a little different -- __block object pointer variables are by default retained in ARC, unlike in MRC. Thus, it will cause a retain cycle. It is necessary for the block to capture a weak reference to itself (using __weak) in order to not have a retain cycle.
However, we still need a strong reference to the block somewhere. If there are no strong references, the block (which is on the heap since it's copied) will be deallocated. Thus, we need two variables, one strong and one weak, and inside the block use the weak one to reference itself:
__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
myBlock);