8

基本上,您可以在 Objective-c 中声明一个方法并将每个参数命名两次。

我知道这很强大,但我不太确定如何使用它......

当约翰向凯利打招呼时:

[ p Greet:"John" toPerson:"Kelly" greetWith:"hey babe" ] ;

关于它的某些内容不自然地阅读。我不确定一个有经验的 Objective-c 程序员是否会这样写那个“信息”。

有人可以解释每个参数有两个名称的原因,并且可能是一个更有用的例子来说明如何有效地在程序中赋予意义?

还有一些事情让我感到困扰,那就是第一个参数的名称与“消息”的名称基本相同。您如何通过编写有意义且易于理解的方法/“消息名称”来解决这个问题?

#import <Foundation/Foundation.h>

@interface 人:NSObject
{
}

-(void)Greet:(char*)from toPerson:(char*)to greetWith:(char*)greeting ;

@结尾

@实现人

-(void)Greet:(char*)from toPerson:(char*)to greetWith:(char*)greeting ;
{
  printf( "%s 对 %s 说 %s\n", from, greeting, to ) ;
}

@结尾



int main (int argc, const char * argv[])
{
  NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];


  人 * p = [ 人分配 ] ;

  [ p Greet:"John" toPerson:"Kelly" greetWith:"hey babe"] ;
  [ p Greet:"Kelly" toPerson:"John" greetWith:"get bent"] ;

  [p释放];



  [池排水];
  返回0;
}

4

5 回答 5

20

首先要做的事情:作为风格说明,将您的牙套放在一起:

[ Person alloc ]

应该

[Person alloc]

我还注意到您在分配 Person 时忘记初始化它,您应该使用:

Person *p = [[Person alloc] init];

了解如何声明方法需要一点时间。检查框架如何命名其方法很有用。对于您的具体示例,我认为您过度工程化。你正在寻找这样的东西:

Person *john = [[Person alloc] initWithName:@"John"];
Person *kelly = [[Person alloc] initWithName:@"Kelly"];

[john greetPerson:kelly withGreeting:@"Hey babe."];
[kelly greetPerson:john withGreeting:@"Get bent."];

请注意,我也没有大写gin greetPerson。这是 Objective-C 的风格惯例。

不要忘记一个对象有它自己的身份,所以你很少需要在一个对象(用来代表一个人)与某人交谈之前指示它是谁。当你写消息时,它应该读起来像英语。当你遇到多个论点时——诚然,很少见——开始用逗号思考:

[john sendEmailToPerson:kelly withSubject:subject body:body attachments:nil];

看看它是如何流动的?甚至还有一些不足之处,我也没有掌握这个。给它点时间。

一个非常有用的文档是 Apple 的Cocoa 编码指南


此外,让自己摆脱 C 陷阱。这是我编写整个程序的方式(我正在介绍一大堆概念,所以不要指望理解所有内容):

#import <Foundation/Foundation.h>

@interface Person : NSObject {
    NSString *name;
}

@property (copy) NSString *name;

- (id)init;
- (id)initWithName:(NSString *)nm;
- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt;

@end

@implementation Person
@synthesize name;

- (id)init {
    if (self = [super init]) {
        name = @"James Bond";          // not necessary, but default
    }                                  // values don't hurt.
    return self;
}
- (id)initWithName:(NSString *)nm {
    if (self = [self init]) {
       name = [nm copy];
    }
    return self;
}

- (void)greetPerson:(Person *)who withGreeting:(NSString *)grt {
    NSLog(@"%@ says '%@' to %@", self.name, grt, who.name);
}

- (void)dealloc {
    [name release];
    [super dealloc];
}

@end

int main(int argc, const char * argv[])
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

    Person *john = [[Person alloc] initWithName:@"John"];
    Person *kelly = [[Person alloc] initWithName:@"Kelly"];

    [john greetPerson:kelly withGreeting:@"StackOverflow is great, isn't it?"];
    [kelly greetPerson:john withGreeting:@"Weren't we supposed to flirt?"];

    [john release];
    [kelly release];

    [pool drain];
    return 0;
}

这段代码完全未经测试,所以如果它顺利运行,我会印象深刻。

于 2009-11-08T20:28:54.897 回答
4

其他人已经涵盖了最重要的几点,所以我将权衡一些补充问题:

还有一些事情困扰着我,那就是第一个参数的名称与“消息”的名称基本相同。您如何通过编写有意义且易于理解的方法/“消息名称”来解决这个问题?

处理此问题的最常见方法是使方法名称由“它是什么/做什么”和第一个参数的标签组合而成。例子:

 NSColor * color = [NSColor colorWithDeviceRed:0.5 green:0.5 blue:0.5 alpha:0.5];

有人可以解释每个参数有两个名称的原因,并且可能是一个更有用的例子来说明如何有效地在程序中赋予意义?

快速的回答是,这两个名字是针对不同的受众的。一个是给方法的使用者的,另一个是给方法的作者的。再次考虑上面的例子。方法声明如下所示:

+ (NSColor *)colorWithDeviceRed:(CGFloat)red
                          green:(CGFloat)green
                           blue:(CGFloat)blue
                          alpha:(CGFloat)alpha

当用户调用该方法时,他们关心的是第一个标签(冒号之前的标签)。您可以在我的第一个示例中看到,其中通道值作为数字常量传递,在代码中只能看到标签。

实际的参数名称(类型后面的部分)方法定义中使用,因此实际上仅适用于编写方法的程序员,因为这些变量将在方法主体本身中可用。

于 2009-11-08T20:43:18.240 回答
2

该方法的第一个“部分”是selector,对于您的示例,这包括-greet:toPerson:greetWith:,这是该方法的实际名称。

第二个“部分”是方法的参数,在您的示例中,它们是问候语。

这类似于 C 之类的东西

int greet(string to, string greeting) {
    print(greeting, to);
}

我还应该提到,您可能会想要使用NSString *而不是char *NSLog()而不是printf()(别担心,它的工作原理几乎完全相同)。

于 2009-11-08T20:29:12.730 回答
0

大概会是:

[personJohn greetPerson:@"Kelly" withGreeting:@"hey babe"];

person 对象已经是 John,他正在问候另一个 person 对象,我不会像您那样将其定义为字符串,而是定义为 Person 类的另一个实例,然后您可以这样做greetWithString

[personJohn greetPerson:personKelly withGreeting:@"hey babe"];

您没有两次定义参数,这就是您感到困惑的地方。如果你了解 C++,你通常会:

void greetPerson(Person thePerson, string greeting);

例如函数原型。然后你会这样称呼它:

greetPerson(personKelly, "hey babe");

现在,objective-c 所做的所有事情都是通过自我记录让您轻松。不是简单地将参数放入函数中,而是在声明它们之前命名它们,因此上面的调用将是:

greetPerson(Person:personKelly, greeting:"hey babe");

给定上面发布的函数原型。这样,当您阅读代码时,您就知道每个参数在做什么,因此可以自我记录。一开始可能看起来很乏味,但代码的可读性大大提高了。

于 2009-11-08T20:29:55.093 回答
0

您在上面描述的方法的名称是“Greet:toPerson:greetWith:”。冒号是名称的一部分。参数(及其类型说明符)不是。

样式说明:除非您指的是首字母缩写词(例如“URL”),否则不要以大写字符开头的方法名称。)

于 2009-11-08T20:37:49.247 回答