How to pass a block as selector with param to perf

2019-09-15 16:27发布

问题:

Is it possible to create a block variable as selector accepting parameters, and to pass it to performSelector:withObject:? Currently, writing some tests and want to write a self contained method with all related checking. Need to pass a block, receive the param in it and do some checking in that block. I'm looking for something like:

...
SEL blockAsSelector = ^{(NSString *param){NSLog(@"Passed param = %@", param);}}

[self performSelector:blockAsSelector withObject:stringThatWillBeUsedAsParamInBlock];
...

回答1:

Is it possible to create a block variable as selector accepting parameters, and to pass it to performSelector:withObject:?

No. Blocks and selectors are not the same thing.

In your example, it doesn't make sense. -performSelector:withObject: runs synchronously on the same thread. You might as well just execute the block i.e.

void (^myBlock)(NSString*) = ^(NSString *param){NSLog(@"Passed param = %@", param);};

myBlock(@"foo");

If you want to do the work in the block concurrently, you would use GCD or am NSBlockOperation.



回答2:

If you don't need a delay to perform the operation you can:

[[NSOperationQueue mainQueue] addOperationWithBlock:^(void)block]


回答3:

I generally agree with other answers that you should try to find another way to do this, as selectors and blocks are really not that interchangeable. But if you absolutely had to do it this way, I think something like this would be your best bet:

// BlockWrapper.h

@interface BlockWrapper : NSObject

@property(nonatomic, retain) void (^block)(NSString*);
@property(nonatomic, copy) NSString* string;

@end



// Your other code file

- (void)evaluateBlockWrapper:(BlockWrapper)wrapper {
    wrapper.block(wrapper.string);
}

...
BlockWrapper* wrapper = [[BlockWrapper alloc] init];
wrapper.block = ^(NSString* param) { NSLog(@"Passed param = %@", param); }
wrapper.string = stringThatWillBeUsedAsParamInBlock;

[self performSelector:@selector(evaluateBlockWrapper:) withObject:wrapper];
...

Although this makes me wonder why you want to have the block take a string parameter, instead of just referencing the string inside the block:

// Your other code file

- (void)evaluateBlock:(void (^)(void))block {
    block();
}

...
[self performSelector:@selector(evaluateBlock:)
    withObject:^{
        NSLog(@"Passed param = %@", stringThatWillBeUsedAsParamInBlock);
    }];
...

I'm not too sure about all the memory management here, so someone else will have to double check me on that.