2012年5月22日 星期二

selector 的定義與使用

 A selector is the name used to select a method to execute for an object, or the unique identifier that replaces the name when the source code is compiled. 

 比如对象a有一个方法叫做doSomething,那么可以这么执行:
[a doSomething];
如果用@selector的方式,可以这么做:
[a performSelector:@selector(doSomething)];

@selector() 指令让你可以直接引用编译后的选择器而不是方法全名

用selector來代替method的名字,然後用SEL這個type來暫存selector所對應到的變數

if ([obj respondsToSelector:@selector(shoot)]) {
[obj shoot];
} else if ([obj respondsToSelector:@selector(shootAt:)]) {
[obj shootAt:target];
}
SEL is the Objective-C “type” for a selector

 // 注意變數的數目
SEL shootSelector = @selector(shoot);   // shoot()沒有帶變數


SEL shootAtSelector = @selector(shootAt:); // 帶一個變數


SEL moveToSelector = @selector(moveTo:withPenColor:);  // 帶兩個變數


在编译时使用 @selector() 指令将选择器分配给 SEL 变量是最有效率的。

此處可參考http://blog.csdn.net/datacloud/article/details/7276043


此處可參考程式碼
@implementation ClassForSelectors
- (void) fooNoInputs {
    NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
    NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
    NSLog(@"Logs %@ then %@", first, second);
}
- (void) performMethodsViaSelectors {
    [self performSelector:@selector(fooNoInputs)];
    [self performSelector:@selector(fooOneInput:) withObject:@"first"];
    [self performSelector:@selector(fooFirstInput:secondInput:) 
                  withObject:@"first" withObject:@"second"];
}
@end


方法(method)和选择器(selector)

编译后的选择器只是表示方法的名称,并不是方法的实现。例如,一个类的display方法与其他类中定义的display方法有相同的选择器。这个 概念对于多态和动态绑定非常重要,它使你可以向不同类的接收者发送相同的消息。如果每个方法实现都有一个选择器,那么消息与函数调用就没什么区别了。
同名的类方法和实例方法也有相同的选择器。但是,因为他们处在不同的域,因此不会被混淆。一个类除了可以定义名为display的实例方法外,还可以定义一个名为display的类方法。


方法(method)返回和参数类型

消息机制只能通过选择器来访问方法的实现,因此它对所有具有相同选择器的方法一视同仁。它会从选择器中找到方法的返回类型,以及它的参数数据类型。 因此,除了发送给静态类型接收者的消息外,动态绑定要求所有同名方法的实现都要有相同的返回类型和相同的参数类型。(对这条规则来说,静态类型的接收者是 一个例外,因为编译器能够从类的类型了解方法实现。)
尽管同名的类方法和实例方法有相同的选择器标识,但它们可以有不同的参数类型和返回类型。


執行SEL所對應的method

Using the performSelector: or performSelector:withObject: methods in NSObject
[obj performSelector:shootSelector];
[obj performSelector:shootAtSelector withObject:coordinate];

Using makeObjectsPerformSelector: methods in NSArray[array makeObjectsPerformSelector:shootSelector]; // cool, huh?
[array makeObjectsPerformSelector:shootAtSelector withObject:target]; // target is an id

In UIButton, - (void)addTarget:(id)anObject action:(SEL)action ...;
[button addTarget:self action:@selector(digitPressed:) ...];
 

一個例子
SEL aSelector = @selector(run);
[aDog performSelector:aSelector];
[anAthlete performSelector:aSelector];
[aComputerSimulation performSelector:aSelector];



另外兩個使用例
@selector (alloc)
@selector (setTo:over:)
使用方法例
[Fraction instancesRespondToSelector: @selector (setTo:over:)]


if ( [Square respondsTo: @selector (alloc)] == YES )
//就可以檢查alloc使否為Square的method


以下為較完整片斷

SEL      action;   // 使用SEL type來做為selector的暫存
id       graphicObject;  // 也用dynamic type
...
action = @selector (draw);
...
[graphicObject performSelector: action];

if ([graphicObject respondsToSelector: action] == YES)
      [graphicObject perform: action]
else
      // error handling code here



另外讓SEL可以跟NSString*互換
SEL selector = NSSelectorFromString(@"MyMethod:"); 
 or 
SEL selector = @selector(@"MyMethod:");

SEL setWidthHeight; 
setWidthHeight = @selector(setWidth:height:);
setWidthHeight NSSelectorFromString(aBuffer);

NSString *method; 
method = NSStringFromSelector(setWidthHeight); 
 


使用 @selector() 選取函式時,如該函式有參數,則 1 個參數搭配 1 個冒號,例如 :
     
#沒有參數


        -(void)methodWithNoArguments;
        => SEL noArgumentSelector = @selector(methodWithNoArguments);

 # 1 個參數
   
        -(void)methodWithOneArgument:(id)argument;
        => SEL oneArgumentSelector = @selector(methodWithOneArgument:);

  # 2 個參數

        -(void)methodWIthTwoArguments:(id)argumentOne andVar:(id)argumentTwo;
        => SEL twoArgumentSelector = @selector(methodWithTwoArguments:andVar:);


example: http://blog.csdn.net/gdyer/article/details/7451858
theReceiver是接受消息的对象类型是id,theSelector是消息名称类型是SEL。下边代码我们来看看如何来生成一个SEL,如果传递消息。
首先建立一个简单的函数
- (void) fooNoInputs {
NSLog(@"Does nothing");
}
然后调用它
[self performSelector:@selector(fooNoInputs)];
第二个试验看看如何在消息中传递参数
我们建立一个有input参数的函数
- (void) fooOneIput:(NSString*) first {
NSLog(@"Logs %@", first);
}
然后调用它
[self performSelector:@selector(fooOneInput:) withObject:@"first"];
第三个试验更多的参数
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
NSLog(@"Logs %@ then %@", first, second);
}
然后调用它
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first"withObject:@"second"];
第四个试验如何建立动态的函数,然后调用他们?我们需要建立一个selector
SEL myTestSelector = @selector(myTest:);
并且我们调用的函数在另外一个Class内
- (void)abcWithAAA: (NSNumber *)number {
int primaryKey = [number intValue];
NSLog("%i", primaryKey);
}
MethodForSelectors * mfs = [MethodForSelectors alloc];
NSArray *Arrays = [NSArray arrayWithObjects:@"AAA"@"BBB"nil];
for ( NSString *array in Arrays ){
SEL customSelector =NSSelectorFromString([NSStringstringWithFormat:@"abcWith%@:", array]);
mfs = [[MethodForSelectors allocperformSelector:customSelector withObject:0];
}
完整的代码:
@implementation ClassForSelectors
- (void) fooNoInputs {
NSLog(@"Does nothing");
}
- (void) fooOneIput:(NSString*) first {
NSLog(@"Logs %@", first);
}
- (void) fooFirstInput:(NSString*) first secondInput:(NSString*) second {
NSLog(@"Logs %@ then %@", first, second);
}
- (NSArray *)abcWithAAA: (NSNumber *)number {
int primaryKey = [number intValue];
NSLog("%i", primaryKey);
}
- (void) performMethodsViaSelectors {
[self performSelector:@selector(fooNoInputs)];
[self performSelector:@selector(fooOneInput:) withObject:@"first"];
[self performSelector:@selector(fooFirstInput:secondInput:) withObject:@"first"withObject:@"second"];
}
- (void) performDynamicMethodsViaSelectors {
MethodForSelectors * mfs = [MethodForSelectors alloc];
NSArray *Arrays = [NSArray arrayWithObjects:@"AAA"@"BBB"nil];
for ( NSString *array in Arrays ){
SEL customSelector =NSSelectorFromString([NSStringstringWithFormat:@"abcWith%@:", array]);
mfs = [[MethodForSelectors allocperformSelector:customSelector withObject:0];
}
}
@end
 
@implementation MethodForSelectors
- (void)abcWithAAA: (NSNumber *)number {
NSLog("%i", number);
}
@end


參考 http://danal.blog.51cto.com/3353275/633874

Selector是 Objective-C一个非常强大的特性,合理使用Selector可以大大简化实现并避免重复代码。但NSObject提供 的performSelector最多只支持两个参数,对于两个以上的参数就无能为力了。一番调查后针对NSObject增加了如下扩展,使得 performSelector可以支持传入参数数组。多个参数就不再是问题了。

@interface NSObject (Addition)
- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects;
@end
@implementation NSObject (Addition)
- (id)performSelector:(SEL)selector withObjects:(NSArray *)objects {
    NSMethodSignature *signature = [self methodSignatureForSelector:selector];
    if (signature) {
        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:signature];
        [invocation setTarget:self];
        [invocation setSelector:selector];
        for(int i = 0; i < [objects count]; i++){
            id object = [objects objectAtIndex:i];
            [invocation setArgument:&object atIndex: (i + 2)];       
        }
        [invocation invoke];
        if (signature.methodReturnLength) {
            id anObject;
            [invocation getReturnValue:&anObject];
            return anObject;
        } else {
            return nil;
        }
    } else {
        return nil;
    }
}
@end

沒有留言: