您可以在objective-c中声明一个方法,并且基本上将 每个参数命名为 。
我认为这很强大,但我还不确定如何使用它......
John Greets Kelly:
[ p Greet:"John" toPerson:"Kelly" greetWith:"hey babe" ] ;
关于它的一些东西不能自然地阅读。我不确定这是一位经验丰富的Objective-c程序员是如何编写“消息”的。
有人可以解释每个参数的两个名称的原因,并且可能是一个更有用的例子,说明如何有效地使用它来在程序中加入意义吗?
同样令我感到困扰的是,第一个参数的名称与“消息”的名称基本相同。你如何通过编写有意义且易于理解的方法/'消息名称'来解决这个问题?
#import <Foundation/Foundation.h> @interface Person : NSObject { } -(void)Greet:(char*)from toPerson:(char*)to greetWith:(char*)greeting ; @end @implementation Person -(void)Greet:(char*)from toPerson:(char*)to greetWith:(char*)greeting ; { printf( "%s says %s to %s\n", from, greeting, to ) ; } @end int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Person * p = [ Person alloc ] ; [ p Greet:"John" toPerson:"Kelly" greetWith:"hey babe" ] ; [ p Greet:"Kelly" toPerson:"John" greetWith:"get bent" ] ; [ p release ] ; [pool drain]; return 0; }
答案 0 :(得分: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."];
请注意,我还没有将g
中的greetPerson
大写。这是Objective-C的风格惯例。
不要忘记一个对象有自己的身份,所以你很少需要在与某人交谈之前指示一个对象(意味着代表一个人)。当你写一条消息时,它应该像英语一样。当你进入多个论点 - 不可否认,很少见 - 开始用逗号思考:
[john sendEmailToPerson:kelly withSubject:subject body:body attachments:nil];
看看它是如何流动的?即使这样做还有一些不足之处,我也没有掌握这一点。给它时间。
一个非常有用的文件是Apple的Coding Guidelines for 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;
}
此代码完全未经测试,因此如果它顺利运行,我将会留下深刻的印象。
答案 1 :(得分:4)
其他人已经涵盖了最重要的一点,所以我只想谈谈一些补充问题:
也有些困扰我,那就是第一个参数的名称与'message'的名称基本相同。你如何通过编写有意义且易于理解的方法/'消息名称'来解决这个问题?
最常见的处理方法是将方法名称组合为“它是什么/做什么”和第一个参数的标签。例如:
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
当用户调用该方法时,他们会关注第一个标签(冒号前面的标签)。您可以在我的第一个示例中看到,通道值作为数字常量传递,只在代码中看到标签。
实际的参数名称(类型之后的部分)在方法定义中使用,因此实际上只有编写方法的程序员才能使用,因为那些是变量将在方法正文中提供。
答案 2 :(得分:2)
方法的第一个“部分”是selector
,对于您的示例,这包括-greet:toPerson:greetWith:
,这是方法的实际名称。
第二个“部分”是方法的参数,在你的例子中是问候语。
这类似于C所在的地方
int greet(string to, string greeting) {
print(greeting, to);
}
我还应该提一下,您可能希望使用NSString *
代替char *
和NSLog()
代替printf()
(不要担心,它工作几乎完全相同)。
答案 3 :(得分:0)
可能是:
[personJohn greetPerson:@"Kelly" withGreeting:@"hey babe"];
person对象已经是John了,他正在问候另一个人对象,我不会像你那样定义为字符串,而是作为Person类的另一个实例,然后你可以做greetWithString
。< / p>
[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");
给出上面发布的函数原型。这样,当您阅读代码时,您就知道每个参数正在做什么,因此是自我记录。起初看起来可能很乏味,但代码可读性大大提高。
答案 4 :(得分:0)
您在上面描述的方法的名称是“Greet:toPerson:greetWith:”。冒号是名称的一部分。参数(及其类型说明符)不是。
样式注释:除非您指的是首字母缩略词(如“URL”),否则不要使用大写字符启动方法名称。