That's a good question. I'm not really sure, but I'm almost positive it's related to Ruby or RubyMotion internals, not ARC in general.
As best I can tell from the article and the filed bug, it comes down to not retaining captured variables in blocks. In Objective-C, there's some automatic memory management that happens for you when you capture a variable in a block:
id x = ...;
^{ NSLog(@"%@", x); };
Because the block depends on x, the lifetime of that object needs to be tied to the lifetime of the block. As such, the compiler emits code so that if and when you copy the block onto the heap, it automatically retains x. When the block object is destroyed, it automatically releases x.
Note that, while definitely "automatic reference counting", this isn't, strictly speaking, ARC. Because this is so critical to being able to use blocks without going completely insane, this bit of cleverness was introduced with blocks on 10.6, even though ARC didn't exist yet.
The note in the bug says that it's complicated because they don't want to introduce a performance regression. This suggests that they're not having trouble with retaining objects referenced by the block per se, but rather with being smart about it, so that it's only retained when necessary. The Objective-C compiler does this by constructing blocks on the stack, and requiring an explicit copy to move them to the heap. Only when explicitly copied do they retain the variables they capture, so simple inline cases remain fast. Perhaps Ruby or RubyMotion have something that makes this harder to do.
If that's correct, then I can't say I find the excuse a very good one. Performance regressions are bad, but generating incorrect code is much worse. They need to fix it immediately, take the speed hit, then see about ways to improve performance while maintaining correctness. However, I certainly could be wrong.
I just want to add that RubyMotion is also not correctly capturing the "value" of the variable in a block. i.e. even if you manually retain a local variable's object and don't release it, it wouldn't work correctly if the block runs after the local variable goes out of scope. IMO, this makes it much harder to workaround this retain bug.
The workaround now is just to create a class around each block operation. I've been thinking about this issue quite a bit (I intrigued many developers using RM are actually not observing this issue sooner) and this workaround seems to be the only way to use APIs like #beginBackgroundTaskWithExpirationHandler: and #endBackgroundTask: which has no non-block based alternatives and is always called asynchronously.
That's quite weird. I can only assume that normal Ruby has no problem with this. Wonder what changed in RubyMotion to break it. Certainly would need to be fixed before I'd call RM anything other than a toy or experiment.
As best I can tell from the article and the filed bug, it comes down to not retaining captured variables in blocks. In Objective-C, there's some automatic memory management that happens for you when you capture a variable in a block:
Because the block depends on x, the lifetime of that object needs to be tied to the lifetime of the block. As such, the compiler emits code so that if and when you copy the block onto the heap, it automatically retains x. When the block object is destroyed, it automatically releases x.Note that, while definitely "automatic reference counting", this isn't, strictly speaking, ARC. Because this is so critical to being able to use blocks without going completely insane, this bit of cleverness was introduced with blocks on 10.6, even though ARC didn't exist yet.
The note in the bug says that it's complicated because they don't want to introduce a performance regression. This suggests that they're not having trouble with retaining objects referenced by the block per se, but rather with being smart about it, so that it's only retained when necessary. The Objective-C compiler does this by constructing blocks on the stack, and requiring an explicit copy to move them to the heap. Only when explicitly copied do they retain the variables they capture, so simple inline cases remain fast. Perhaps Ruby or RubyMotion have something that makes this harder to do.
If that's correct, then I can't say I find the excuse a very good one. Performance regressions are bad, but generating incorrect code is much worse. They need to fix it immediately, take the speed hit, then see about ways to improve performance while maintaining correctness. However, I certainly could be wrong.