我正在学习Objective C,并在阅读方法时注意到这个时髦的怪癖。
与Java和C ++一样,Obj.C可以接受多个参数,这很好,但是它表明客观的C方法可以有多个名称,这些名称似乎不适合我。
例如:
-(NSArray *)shipsAtPoint:(CGPoint)bombLocation withDamage:(BOOL)damaged;
在上面的例子中,有两个参数,bombLocation(返回类型CGPoint)和损坏的(返回类型BOOL),并且方法名称旁边似乎被拆分为shipsatpoint:withDamage
我不明白这是怎么回事...... 当它声明方法可以有多个名称时,它意味着什么? 这仅适用于需要多个参数的方法吗?或者,假设我想用单个名称命名我的方法,但是为它提供了多个参数,是可能的还是我必须为它提供多个名称,每个名称对应一个参数?如果是,那么为什么?
感谢您加入我的困惑! :)
答案 0 :(得分:6)
原因是让它更容易理解。
使用您的示例,该方法在C ++中将是这样的:
int shipsAtPointWithDamage (CGPoint bomb, BOOL damage) //I don't really know C++
好的,所以第一个参数是船的点,损坏是第二个参数。这很容易弄明白,但事情就是这样,你必须弄清楚,你必须看看方法,试图找出每件事情。
在Objective-C中你有
-(NSArray *)shipsAtPoint:(CGPoint)bombLocation withDamage:(BOOL)damaged;
每个参数都有明确的定义,第一个是船的点,第二个是损坏。 它读起来像一个句子,而使用C ++(以及几乎所有其他语言)则不然。
如果你想让一个方法在Obj-C中有多个参数,你必须这样写:
-(returnType)paraOne:(type*)name paraTwo:(type*)name
这是需要习惯的东西,每种语言都不同。一旦你习惯了Objective-C做事的方式,你会认为这绝对是太棒了。
编辑:正如filipe指出的那样,因为该方法作为多个参数并不意味着它有多个名称,在上面给出的示例中,方法名称为paraOne:paraTwo
,而不是{{1} }
答案 1 :(得分:3)
Objective-C使用基于选择器的消息传递系统。这与方法调用不完全相同。当你看到这样的代码时:
[world shipsAtPoint:point withDamage:YES];
将其转换为以下C调用(在最常见的情况下):
objc_msgSend(world, @selector(shipsAtPoint:withDamage:), point, YES);
@selector()
构造返回唯一标识符。该标识符的确切格式是内部实现细节。
objc_msgSend
包含了十几个字节的汇编程序。但是在最简单的情况下,它会查找world
的类,遍历一个选择器表,直到找到匹配shipsAtPoint:withDamage:
的那个,然后在该槽位抓取函数指针。然后跳转到该函数指针,剩下其余的参数(在寄存器或堆栈中,适合处理器)。该位置的函数是您的方法,它根据您的声明知道其参数的顺序和类型。
对你而言,重要的是选择器是shipsAtPoint:withDamage:
。这通常是该方法的唯一名称。你建议没有“多个名字”。 (通常...... Objective-C运行时非常强大,可以将多个选择器指向同一个实现。)
Joe指出,选择器的格式可以是foo::
。这将代表一个采用两个参数的方法,并将被称为[world foo:point :YES]
。你永远不应该这样做。阅读令人难以置信的困惑。但这是合法的。
答案 2 :(得分:2)
Here是我见过的最好的解释。它包括与C ++ / C的比较以及许多其他好的信息。
答案 3 :(得分:2)
我觉得你很困惑。方法不能有多个名称,但参数在标题中的名称可能不同,然后它们就在实现中。
该方法的名称为shipsAtPoint:withDamage:
。这也称为selector
。
此方法返回NSArray
的实例,并接受CGPoint
作为第一个参数,并BOOL
作为第二个参数。
然而,参数的名称可能不同。这完全有效:
// .h file
-(NSArray *)shipsAtPoint:(CGPoint)bombLocation withDamage:(BOOL)damaged;
// .m file
-(NSArray *)shipsAtPoint:(CGPoint)loc withDamage:(BOOL)dmg {
// ...
}
最后,ObjC主要是一些很好的语法糖。您应该知道任何方法调用实际上只归结为某些看起来或多或少类似的C:
objc_msgSend(receiverObj, @selector(shipsAtPoint:withDamage:), point, damage);
所以在一天结束时,你有一个接收器,一个选择器和你的参数。但是ObjC语法要好得多。
答案 4 :(得分:0)
可以提供一种没有标记参数的方法,但显然不鼓励这样做。
-(void)badmethod:(id)obj1:(id)obj2:(id)obj3
{
}
//...
//Usage
[self badmethod:nil :nil :nil];
SEL sel = @selector(badmethod:::);