Ist es möglich, einen Objective-C-Block für das @ selector-Argument in einem UIButton zu übergeben?
Wenn Sie alle bereits bereitgestellten Antworten berücksichtigen, lautet die Antwort Ja, aber ein wenig Arbeit ist erforderlich, um einige Kategorien einzurichten.
Ich empfehle die Verwendung von NSInvocation, da Sie damit viel tun können, z. B. mit Timern, die als Objekt gespeichert und aufgerufen werden ... etc ...
Hier ist, was ich getan habe, aber beachten Sie, dass ich ARC verwende.
Erstens ist eine einfache Kategorie auf NSObject:
.h
@interface NSObject (CategoryNSObject)
- (void) associateValue:(id)value withKey:(NSString *)aKey;
- (id) associatedValueForKey:(NSString *)aKey;
@end
.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
Als nächstes folgt eine Kategorie in NSInvocation, die in einem Block gespeichert werden soll:
.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
.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
So verwenden Sie es:
NSInvocation *invocation = [NSInvocation invocationWithTarget:self block:^(id target) {
NSLog(@"TEST");
}];
[invocation invoke];
Mit dem Aufruf und den Standard-Objective-C-Methoden können Sie viel tun. Beispielsweise können Sie NSInvocationOperation (initWithInvocation :), NSTimer (ScheduledTimerWithTimeInterval: Aufruf: Wiederholungen :) verwenden.
Der Punkt ist, Ihren Block in eine NSInvocation zu verwandeln, ist vielseitiger und kann als solche verwendet werden:
NSInvocation *invocation = [NSInvocation invocationWithTarget:self block:^(id target) {
NSLog(@"My Block code here");
}];
[button addTarget:invocation
action:@selector(invoke)
forControlEvents:UIControlEventTouchUpInside];
Auch dies ist nur ein Vorschlag.
objc_implementationWithBlock()
undclass_addMethod()
lösen können als zugehörige Objekte (was eine Hash-Suche impliziert, die nicht so effizient ist wie die Methodensuche). Wahrscheinlich ein irrelevanter Leistungsunterschied, aber es ist eine Alternative.