Reputation: 57
In Objective-C, is a Block an object? Can it be retained/released? Can it be sub-classed?
Upvotes: 2
Views: 749
Reputation: 54600
Lets look at this, for example:
- (void)doSomeStuffWithABlock
{
void(^myBlock)(NSUInteger, NSString *, NSString *) = ^(NSUInteger index, NSString *string, NSString *string) {
// Do stuff
};
myBlock(1, @"two", @"three"); // Set breakpoint here to inspect myBlock.
}
In the debugger:
(lldb) po myBlock
<__NSMallocBlock__: 0x17d21f20>
(lldb) p * myBlock
(__block_literal_generic) $1 = 0x001cc801 MyApp`__68-[MyObject myMethod]_block_invoke + 1 at MYMyObject.m:218
(lldb) p (BOOL)[myBlock isKindOfClass:[NSObject class]]
(BOOL) $5 = YES
You can send it retain
/ release
, if you're not using ARC. You can also ask for it's retainCount
. However block.h declares these macros that you should use:
#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
I don't think you can subclass it, since no headers publicly expose __NSMallocBlock__
or related Block types (see comments) (that I could find), and I suspect down that road lies nothing but the most excruciating pain, since you'll be trying to trick the compiler. I'm not sure why you'd even want to do that. If you need to add functionality, consider creating your own object that wraps a @property
that is the actual block to execute. Or consider using NSBlockOperation.
Upvotes: 1
Reputation: 108101
Yes, it's an object type.
However it's mostly handled by the compiler, so you can't subclass it and you have very little control over memory management. You typically can only copy
it to the heap, in case it outlives the scope it's declared in.
Concretely, at runtime a block is an instance of either __NSMallockBlock__
, __NSStackBlock__
or __NSGlobalBlock__
. You can read more on the subject here: http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html
Upvotes: 5
Reputation: 53950
In addition to Gabriele's answer, which is correct, you can see it by sending a class
message to a block:
#import <objc/message.h>
int main( void )
{
void ( ^ block )( void ) = ^( void )
{};
NSLog( @"%@", ( ( id ( * )( id, SEL ) )objc_msgSend )( ( id )block, @selector( class ) ) );
return 0;
}
A non-object type would eventually crash, but with a block, you'll get __NSGlobalBlock__
printed, meaning a block is a real (even if obviously special) instance of an Objective-C class.
Upvotes: 1