Bil*_*iff 90 cocoa-touch objective-c
是否可以为@selector一个UIButton?中的参数传递一个Objective-C块?即,有没有办法让以下工作?
[closeOverlayButton addTarget:self
action:^ {[anotherIvarLocalToThisMethod removeFromSuperview];}
forControlEvents:UIControlEventTouchUpInside];
Run Code Online (Sandbox Code Playgroud)
谢谢
Dav*_*ong 69
是的,但你必须使用一个类别.
就像是:
@interface UIControl (DDBlockActions)
- (void) addEventHandler:(void(^)(void))handler
forControlEvents:(UIControlEvents)controlEvents;
@end
Run Code Online (Sandbox Code Playgroud)
实现会有点棘手:
#import <objc/runtime.h>
@interface DDBlockActionWrapper : NSObject
@property (nonatomic, copy) void (^blockAction)(void);
- (void) invokeBlock:(id)sender;
@end
@implementation DDBlockActionWrapper
@synthesize blockAction;
- (void) dealloc {
[self setBlockAction:nil];
[super dealloc];
}
- (void) invokeBlock:(id)sender {
[self blockAction]();
}
@end
@implementation UIControl (DDBlockActions)
static const char * UIControlDDBlockActions = "unique";
- (void) addEventHandler:(void(^)(void))handler
forControlEvents:(UIControlEvents)controlEvents {
NSMutableArray * blockActions =
objc_getAssociatedObject(self, &UIControlDDBlockActions);
if (blockActions == nil) {
blockActions = [NSMutableArray array];
objc_setAssociatedObject(self, &UIControlDDBlockActions,
blockActions, OBJC_ASSOCIATION_RETAIN);
}
DDBlockActionWrapper * target = [[DDBlockActionWrapper alloc] init];
[target setBlockAction:handler];
[blockActions addObject:target];
[self addTarget:target action:@selector(invokeBlock:) forControlEvents:controlEvents];
[target release];
}
@end
Run Code Online (Sandbox Code Playgroud)
一些解释:
DDBlockActionWrapper.这是一个简单的类,它具有一个块属性(我们想要调用的块),以及一个简单地调用该块的方法.UIControl类别简单地实例化这些包装中的一个,将其提供给被调用的块,然后告诉本身使用该包装件和其invokeBlock:作为目标和动作方法(正常).UIControl类别使用关联对象来存储数组DDBlockActionWrappers,因为UIControl它不保留其目标.此数组用于确保在应该调用块时存在块.DDBlockActionWrappers在对象被销毁时清理它,所以我们正在做一个令人讨厌的黑客-[UIControl dealloc]用一个新的删除关联对象,然后调用原始dealloc代码.棘手,棘手.最后,此代码在浏览器中输入,尚未编译.它可能有些问题.你的旅费可能会改变.
lem*_*nar 41
块是对象.将您的块作为target参数传递,@selector(invoke)作为action参数,如下所示:
id block = [^{NSLog(@"Hello, world");} copy];// Don't forget to -release.
[button addTarget:block
action:@selector(invoke)
forControlEvents:UIControlEventTouchUpInside];
Run Code Online (Sandbox Code Playgroud)
Bol*_*ock 17
不,选择器和块在Objective-C中不是兼容类型(事实上,它们是非常不同的东西).你必须编写自己的方法并改为传递它的选择器.
是否可以在UIButton中传递@selector参数的Objective-C块?
接受所有已经提供的答案,答案是肯定的,但是设置一些类别需要做一些工作.
我建议使用NSInvocation因为你可以做很多事情,比如定时器,存储为对象和调用...等...
这是我做的,但请注意我使用的是ARC.
首先是NSObject上的一个简单类别:
.H
@interface NSObject (CategoryNSObject)
- (void) associateValue:(id)value withKey:(NSString *)aKey;
- (id) associatedValueForKey:(NSString *)aKey;
@end
Run Code Online (Sandbox Code Playgroud)
.M
#import "Categories.h"
#import <objc/runtime.h>
@implementation NSObject (CategoryNSObject)
#pragma mark Associated Methods:
- (void) associateValue:(id)value withKey:(NSString *)aKey {
objc_setAssociatedObject( self, (__bridge void *)aKey, value, OBJC_ASSOCIATION_RETAIN );
}
- (id) associatedValueForKey:(NSString *)aKey {
return objc_getAssociatedObject( self, (__bridge void *)aKey );
}
@end
Run Code Online (Sandbox Code Playgroud)
接下来是NSInvocation上要存储在块中的类别:
.H
@interface NSInvocation (CategoryNSInvocation)
+ (NSInvocation *) invocationWithTarget:(id)aTarget block:(void (^)(id target))block;
+ (NSInvocation *) invocationWithSelector:(SEL)aSelector forTarget:(id)aTarget;
+ (NSInvocation *) invocationWithSelector:(SEL)aSelector andObject:(__autoreleasing id)anObject forTarget:(id)aTarget;
@end
Run Code Online (Sandbox Code Playgroud)
.M
#import "Categories.h"
typedef void (^BlockInvocationBlock)(id target);
#pragma mark - Private Interface:
@interface BlockInvocation : NSObject
@property (readwrite, nonatomic, copy) BlockInvocationBlock block;
@end
#pragma mark - Invocation Container:
@implementation BlockInvocation
@synthesize block;
- (id) initWithBlock:(BlockInvocationBlock)aBlock {
if ( (self = [super init]) ) {
self.block = aBlock;
} return self;
}
+ (BlockInvocation *) invocationWithBlock:(BlockInvocationBlock)aBlock {
return [[self alloc] initWithBlock:aBlock];
}
- (void) performWithTarget:(id)aTarget {
self.block(aTarget);
}
@end
#pragma mark Implementation:
@implementation NSInvocation (CategoryNSInvocation)
#pragma mark - Class Methods:
+ (NSInvocation *) invocationWithTarget:(id)aTarget block:(void (^)(id target))block {
BlockInvocation *blockInvocation = [BlockInvocation invocationWithBlock:block];
NSInvocation *invocation = [NSInvocation invocationWithSelector:@selector(performWithTarget:) andObject:aTarget forTarget:blockInvocation];
[invocation associateValue:blockInvocation withKey:@"BlockInvocation"];
return invocation;
}
+ (NSInvocation *) invocationWithSelector:(SEL)aSelector forTarget:(id)aTarget {
NSMethodSignature *aSignature = [aTarget methodSignatureForSelector:aSelector];
NSInvocation *aInvocation = [NSInvocation invocationWithMethodSignature:aSignature];
[aInvocation setTarget:aTarget];
[aInvocation setSelector:aSelector];
return aInvocation;
}
+ (NSInvocation *) invocationWithSelector:(SEL)aSelector andObject:(__autoreleasing id)anObject forTarget:(id)aTarget {
NSInvocation *aInvocation = [NSInvocation invocationWithSelector:aSelector
forTarget:aTarget];
[aInvocation setArgument:&anObject atIndex:2];
return aInvocation;
}
@end
Run Code Online (Sandbox Code Playgroud)
以下是如何使用它:
NSInvocation *invocation = [NSInvocation invocationWithTarget:self block:^(id target) {
NSLog(@"TEST");
}];
[invocation invoke];
Run Code Online (Sandbox Code Playgroud)
您可以使用调用和标准Objective-C方法做很多事情.例如,您可以使用NSInvocationOperation(initWithInvocation :),NSTimer(scheduledTimerWithTimeInterval:invocation:repeates :)
关键是将您的块转变为NSInvocation更通用,可以这样使用:
NSInvocation *invocation = [NSInvocation invocationWithTarget:self block:^(id target) {
NSLog(@"My Block code here");
}];
[button addTarget:invocation
action:@selector(invoke)
forControlEvents:UIControlEventTouchUpInside];
Run Code Online (Sandbox Code Playgroud)
这只是一个建议.
小智 5
不幸的是,并不那么简单.
从理论上讲,可以定义一个函数,该函数动态地向该类添加一个方法target,让该方法执行一个块的内容,并根据action参数的需要返回一个选择器.这个函数可以使用MABlockClosure使用的技术,在iOS的情况下,它依赖于libffi的自定义实现,这仍然是实验性的.
你最好把这个动作作为一种方法来实现.
| 归档时间: |
|
| 查看次数: |
38774 次 |
| 最近记录: |