问题
I'm creating a barButton which when pressed should set the editing mode of a UITableView to yes. Here's my code:
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: @"Edit"
style: self.navigationController.navigationItem.leftBarButtonItem.style
target: self
action: ];
What I don't understand is what I need to put as an argument for the action
part so that I can execute a code block there. I could easily enough put @selector(someMethod)
but I'm only executing one or two lines and creating another method is pretty pointless.
Thanks for any help!
回答1:
Further to pgb's comment, writing something like this would solve the problem:
@interface PJBlockHolder
+ (id)blockHolderWithBlock:(dispatch_block_t)block;
- (void)invoke;
@end
/* obvious implementation; copy the block, issue it upon invoke */
And:
[[UIBarButtonItem alloc] initWithTitle: @"Edit"
style: self.navigationController.navigationItem.leftBarButtonItem.style
target: [PJBlockHolderWithBlock:^{ /* your code here */ }]
action:@selector(invoke) ];
So you've created a custom object that wraps a block and issues it upon a particular selector.
EDIT: as noted below, UIControl
s don't retain their targets. So probably the easiest thing is to tie the lifetime of the block holder to the lifetime of the control; that's not necessarily ideal because then the holder will outlive its usefulness if you subsequently remove it as a target while keeping the control alive, but it's probably suitable for the majority of cases.
Options are either to use Objective-C's built in associated objects, or to use the fact that UIControl
inherits from UIView
, giving it a CALayer
, which can store arbitrary keyed objects.
Justin Spahr-Summers links to a well documented, public domain implementation of the former in his comment below so I'll show an example of the latter, even though it's hacky, for the purposes of discussion.
PJBlockHolderWithBlock *blockHolder = [PJBlockHolderWithBlock:^{ /* your code here */ }];
UIBarButtonItem *barButtonItem =
[[UIBarButtonItem alloc] initWithTitle: @"Edit"
style: self.navigationController.navigationItem.leftBarButtonItem.style
target: blockHolder
action:@selector(invoke) ];
[barButtonItem.layer setValue:blockHolder forKey:@"__myBlockHolderKey__"];
回答2:
You can't do it as you intend. The target:
action:
parameters are intended to send an object and a selector to be called on that object. As far as I know, there's no equivalent API that uses blocks.
来源:https://stackoverflow.com/questions/11318519/executing-code-block-in-place-of-selector