Objective-C _cmd用法

_cmd 是隐藏的参数,代表当前方法的 selector,它和 self 一样都是每个方法调用时都会传入的参数,动态运行时会提及如何传的这两个参数。

比如这样一个语句:

1
2
3
4
5
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(@"Current method: %@ %@", [self class],NSStringFromSelector(_cmd));
}

控制台输出:

1
Current method: FirstViewController viewDidLoad

其实我更加喜欢这样:

1
2
3
4
5
- (void)viewDidLoad
{
NSLog(@"%s", __PRETTY_FUNCTION__);
// ...

}

控制台输出:

1
-[MyViewController viewDidLoad]

实例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//比如需要打印当前被调用的方法,可以在一个方法中添加:
NSLog(@"%@ call",NSStringFromSelector(_cmd));
//会输出类似
//2013-01-10 11:25:46.902 TDDataViewer[855:303] applicationDidFinishLaunching: call
//这样的内容。

//在cocos2d中,_cmd通常用于定时调用某个函数(schedule)
//比如下面方法利用_cmd能够不定时地调用某个函数
-(void) scheduleUpdates {
// schedule the first update as usual
[self schedule:@selector(irregularUpdate:) interval:1];
}
-(void) irregularUpdate:(ccTime)delta {
// unschedule the method first [self unschedule:_cmd];
// I assume you’d have some kind of logic other than random to determine
// the next time the method should be called
float nextUpdate = CCRANDOM_0_1() * 10;
// then re-schedule it with the new interval using _cmd as the selector
[self schedule:_cmd interval:nextUpdate];
}

实例2:

performSelector -> _cmd -> objc_msgSend -> id (*IMP) (id, SEL, …)
Raw

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
//普通的
- (NSInteger)fibonacci:(NSInteger)n {
if (n > 2) {
return [self fibonacci:n - 1] + [self fibonacci:n - 2];
}
return n > 0 ? 1 : 0;
}

//改成用_cmd实现就变成了这样:
- (NSInteger)fibonacci:(NSInteger)n {
if (n > 2) {
return (NSInteger)[self performSelector:_cmd withObject:(id)(n - 1)] + (NSInteger)[self performSelector:_cmd withObject:(id)(n - 2)];
}
return n > 0 ? 1 : 0;
}

//或者直接用objc_msgSend:
- (NSInteger)fibonacci:(NSInteger)n {
if (n > 2) {
return (NSInteger)objc_msgSend(self, _cmd, n - 1) + (NSInteger)objc_msgSend(self, _cmd, n - 2);
}
return n > 0 ? 1 : 0;
}

//但是每次都通过objc_msgSend来调用显得很费劲,有没有办法直接进行方法调用呢?答案是有的,这就需要用到IMP了。IMP的定义为“id (*IMP) (id, SEL, …)”,也就是一个指向方法的函数指针。
//NSObject提供methodForSelector:方法来获取IMP,因此只需稍作修改就行了:
- (NSInteger)fibonacci:(NSInteger)n {
static IMP func;
if (!func) {
func = [self methodForSelector:_cmd];
}

if (n > 2) {
return (NSInteger)func(self, _cmd, n - 1) + (NSInteger)func(self, _cmd, n - 2);
}
return n > 0 ? 1 : 0;
}

//延迟
[self performSelector:@selector(performDismiss) withObject:nil afterDelay:3.0f];

//在其他Class调用
//首先new一下class,然后就可以用class里边的Function了
Fraction *frac = [[Fraction alloc] init];
[frac setNumerator: 1];
[frac setDenominator: 3];

//或者
[[Fraction alloc] performSelector:@selector(performDismiss) withObject:nil afterDelay:3.0f];

以上