ARC not copying block, crashes when setting to nil.
| Originator: | adam | ||
| Number: | rdar://11986295 | Date Originated: | 30-Jul-2012 12:17 PM |
| Status: | Open | Resolved: | |
| Product: | iPhone SDK | Product Version: | 5 or 6 |
| Classification: | Important | Reproducible: | Always |
30-Jul-2012 12:17 PM Adam McNamara: Summary: We have a UITableViewCell subclass that had a block called "action" as an ivar. In prepareForReuse, we'd set action = nil;. ARC wasn't copying the block when assigning to the ivar, so we'd crash in prepareForReuse. It would only appear in an Ad Hoc build on device. It was not present during debug builds or in the simulator. Steps to Reproduce: 1. Create a UITableView subclass with a block as an ivar. 2. Set ivar = block. 3. In prepareForReuse, set the block = nil. 4. Install as an ad hoc build on device. Expected Results: The ivar should be nil'd out properly. Actual Results: The application crashes with Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_INVALID_ADDRESS at 0xc5f6c046 in prepareForReuse. Regression: Notes: 1. This only happened on an Ad Hoc build. 2. Turning the block into a @property (nonatomic, copy) BlockType action; and using self.action = nil worked.
Comments
Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!
I just happened to glance at this and wanted to say that this is crashing because the address that it holds is no longer valid (as the error says) since it was a stack address. ARC only copies blocks to the heap when returning them because it knows that a copy is required to keep the block's memory intact in this case. (Of course there's nested block copy behavior from pre-ARC as well). I suppose ARC doesn't copy for performance reasons because technically you could call a method directly after setting the ivar that accesses it perfectly fine since it's still on the stack. From the documentation:
Blocks “just work” when you pass blocks up the stack in ARC mode, such as in a return. You don’t have to call Block Copy any more. You still need to use [^{} copy] when passing “down” the stack into arrayWithObjects: and other methods that do a retain.