문제

Of all the things that I would expect to support blocks, NSUndoManager curiously does not seem to do so. Is there some inherent reason for this, or has Apple simply not gotten around to modernizing this bit of API?

In particular I would like to define a method on NSObject,

- (void)performBlock {
    void (^block)(void) = (id)self;
    block();
}

in order to be able to call,

[[undoManager prepareWithInvocationTarget:^{
    NSLog( @"hello world" );
}] performBlock];

Have I missed something? Is there anything wrong with this?

(Inspired by an 2009 Mike Ash article, which recommends not defining methods on blocks. I left a comment there, too.)

도움이 되었습니까?

해결책

I think Mike's main contention is that it makes for code that's hard to read, not that there's a fundamental problem with this idea.

However, I see a couple problems with what you've written. For one, you're adding a category method on NSObject, but if you call it on an object that's not a block, it will crash. Perhaps there's a way to fix that, like making the performBlock method simply do nothing if called on a non-block, or at least log an error before crashing. I'm not exactly how this would work.

Also, blocks start out on the stack, so you need to copy them before passing them into a method that keeps them around to be executed later. Methods written to take a block take care of this. Presumably -[NSUndoManager prepareWithInvocationTarget:] does not copy the target passed in. So, you'd need to copy the block yourself (using either -copy or Block_copy()) before you pass it in:

void (^block)(void) = [^{
    NSLog(@"hello world");
} copy];

[[undoManager prepareWithInvocationTarget:block] performBlock];
[block release];

At least in early versions of ARC, this was still a problem because the block is being passed into a method expecting an id (as explained in the Blocks section of Mike Ash's ARC article). Perhaps it has been fixed? I wouldn't count on it...

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top