3329
3329

Reputation: 1513

Is copy the same as Block_copy()?

Are they the same, copy and Block_copy()? How? or if not, what are the differences?

I was curious about this for a while so I decided to do some researches.

See what I found it my answer.

Upvotes: 3

Views: 471

Answers (2)

newacct
newacct

Reputation: 122518

When used on an expression of block pointer type, the method copy and the function Block_copy() are the same. And likewise the method release and the function Block_release() are the same. The methods copy and release are just more Objective-C messaging style, since blocks are objects in Objective-C, and are memory managed using retain and release like other Cocoa objects. On the other hand, when used in C/C++, blocks can only be managed with Block_copy() and Block_release().

Upvotes: 0

3329
3329

Reputation: 1513

Finally, I found the answer. copy and Block_copy() are the same, but not that exactly.

Here is what I found :


Let's take a look at the classes of blocks, there are 3 of them :

  1. __NSGlobalBlock__ - You will get a block of this class if you implement a block without any references to the outside of the block.

    void(^block)() = ^{ NSLog(@"GRAZZZZ"); };
    
  2. __NSStackBlock__ - You will get a block of this class if you implement a block with one or more references to the outside of the block, (you will get this when you are running on non-ARC environment only. In ARC env, ARC copies it for you automatically).

    // NON-ARC CODE
    int theOutsider = 1234;
    void(^block)() = ^{ NSLog(@"%d", theOutsider); };
    
  3. __NSMallocBlock__ - You will get a block of this class if you copy a __NSStackBlock__ block.

    int theOutsider = 1234;
    void(^block1)() = [^{ NSLog(@"%d", theOutsider); } copy]; // NON-ARC VERSION
    void(^block2)() = ^{ NSLog(@"%d", theOutsider); }; // ARC VERSION
    

For __NSGlobalBlock__, when you call copy to it, it does nothing, just return. So, just ignore it. There is no need to move anything to heap. Below is the assembly of -[__NSGlobalBlock copy] (its super class) :

CoreFoundation`-[__NSGlobalBlock copy]:
   0x7fff8bd016f0:  pushq  %rbp
   0x7fff8bd016f1:  movq   %rsp, %rbp
   0x7fff8bd016f4:  movq   %rdi, %rax
   0x7fff8bd016f7:  popq   %rbp
   0x7fff8bd016f8:  ret    
   0x7fff8bd016f9:  nopl   (%rax)

For __NSStackBlock__ and __NSMallocBlock__, when you call copy to them, they forward to copy method of its super class, -[NSBlock copy]. Here is its assembly code on OS X 10.9 SDK :

CoreFoundation`-[NSBlock copy]:
   0x7fff8bcc86a0:  pushq  %rbp
   0x7fff8bcc86a1:  movq   %rsp, %rbp
   0x7fff8bcc86a4:  pushq  %rbx
   0x7fff8bcc86a5:  pushq  %rax
   0x7fff8bcc86a6:  movq   %rdi, %rbx
   0x7fff8bcc86a9:  callq  0x7fff8be360ac            ; symbol stub for: objc_collectingEnabled
   0x7fff8bcc86ae:  movq   %rbx, %rdi
   0x7fff8bcc86b1:  addq   $0x8, %rsp
   0x7fff8bcc86b5:  testb  %al, %al
   0x7fff8bcc86b7:  je     0x7fff8bcc86c0            ; -[NSBlock copy] + 32
   0x7fff8bcc86b9:  popq   %rbx
   0x7fff8bcc86ba:  popq   %rbp
   0x7fff8bcc86bb:  jmpq   0x7fff8be361f6            ; symbol stub for: _Block_copy_collectable
   0x7fff8bcc86c0:  popq   %rbx
   0x7fff8bcc86c1:  popq   %rbp
   0x7fff8bcc86c2:  jmpq   0x7fff8be361f0            ; symbol stub for: _Block_copy
   0x7fff8bcc86c7:  nopw   (%rax,%rax)

The assembly code on iOS 7.1 SDK :

CoreFoundation`-[NSBlock copy]:
   0x17949d0:  pushl  %ebp
   0x17949d1:  movl   %esp, %ebp
   0x17949d3:  popl   %ebp
   0x17949d4:  jmp    0x18d3d8a                 ; symbol stub for: _Block_copy
   0x17949d9:  nopl   (%eax)

As you can see in the code, -[NSBlock copy] does call _Block_copy!.

Enough for copy, let's take a look at Block_copy(). It is defined in Block.h as this :

#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))

Block_copy() does call _Block_copy too!!


To this point, I can summarise that copy and Block_copy() are the same!.

Hope this can help someone with the same curiosity as me :D.

Upvotes: 5

Related Questions