Objective-c和Java之间的字段,我不理解@property和实例变量

时间:2014-01-10 07:21:24

标签: objective-c cocoa

两天前开始学习objective-c的开发人员,我不明白以下两种方法之间的区别:

1

 @interface Person : NSObject

   @property NSString *firstName;
   @property NSString *lastName;

 @end

2

  @interface Person : NSObject{

    NSString *firstName;
    NSString *lastName;
  }

 @end

使用Java语言,我们定义了两个字符串字段:

class Person extends Object{
  (public/private/protected) String firstName;
  (public/private/protected) String lastName;
}

我想知道哪一个(1到2之间)与上面的Java代码具有相同的含义。


非常感谢@iamyogish @ Popeye,如果我的答案是对的,我会纠正你们两个人。 阅读电子书:Objective-C 2.0 Essentials后,我了解到(如果不对,请告诉我。):

@interface Person : NSObject

   @property NSString *firstName;
   @property NSString *lastName;

 @end

这相当于Java代码:

class Person extends Object{
 private  String firstName;
 private String lastName;//In fact:private should be protected
 //setter and getter.
 //you can use ecplise tool to generate setter/getter method automaticly
}

正如您可能想象的那样,必须为大量(1000或更多)复杂类编写这些方法最终会耗费大量时间。 Objective-C提供了合成的访问器方法,所以你应该使用@property和@synthesize指令。如果你编写代码如下:

@interface Person : NSObject

    NSString *firstName;//note that the default access level is protected.
    NSString *lastName;

 @end

不幸的是,您需要提供可以访问实例变量的方法,例如(您可以自己定义函数的名称)

-(NSString ) getFirstName;
-(NSString ) getLastName;
-(void) setFirstName:(NSString * name);
-(void) setLastName:(NSString * name);

除此之外,如果使用@property和@synthesize指令,您可以访问实例变量,如C ++ / JAVA语法点符号,如:

 NSString * firstName= [[Person alloc] init].firstName;

请注意:理解点表示法的一个关键点是它仅适用于已声明合成访问器方法的实例变量。

实例变量的访问级别在类声明的@interface部分中使用@protected,@ private和@public指令指定。

 @interface Person : NSObject
 @public
    NSString *firstName;//note that the default access level is protected.
    NSString *lastName;

 @end

当从另一个类或方法或函数中的任何其他代码访问公共实例变量时, - >使用指针运算符表示法。因此,您可以访问C ++ / C中的Public Filed,如:

  [[Person alloc] init]->firstName = "your first name";

另一个问题是:

  @interface Person : NSObject

   @property NSString *firstName;
   @property NSString *lastName;

 @end

相当于:

@interface Person : NSObject{
   NSString *firstName;
   NSString *lastName;
 }

   @property NSString *firstName;
   @property NSString *lastName;

 @end
是不是?并且ivar等同于实例变量?

4 个答案:

答案 0 :(得分:5)

让我们从(2)

开始
 @interface Person : NSObject
 {
 NSString *firstName;
 NSString *lastName;
 }
 @end

在这种情况下,firstNamelastName对我来说被称为ivarsInstance Variables我通常不会声明ivars。一些开发人员现在说你不应该把它们放在@interface声明中,原因有两个。

  
      
  1. 它向类的用户公开了有关实现的详细信息,这将导致其他开发人员使用或在某些情况下自己依赖应该可用的实现细节。

  2.   
  3. 一些开发人员认为将这些内容放在@interface中会使编译时间显着延长。

  4.   

大多数开发人员认为实现ivar的最佳方法是在使用大括号的@implementation内:

@implementation Person {
    NSString *firstName;
    NSString *lastName;
}

我们将它们放在这里的理论背后的理论是因为理论上它们被声明为私有,阻止任何人了解它们,除了创建该类的开发人员。这将解决所有其他开发人员搞乱他们不应该做的事情。

Java中的等价物就像private String firstName;

一样简单

现在让我们来看看(1)

@interface Person : NSObject

@property NSString *firstName;
@property NSString *lastName;

@end

技术上@properties只需要在需要从其他类访问属性时才能使用,但许多开发人员更喜欢在ivars上使用这些,因为它使它们更易于使用,并且在新版本中xcode这些属性的ivars会在后台自动声明。

通过声明属性,您基本上可以自动为这些属性生成getterssetters。在xcode的早期版本中,您确实需要@synthesize,但不再需要这个版本。因此,声明两个属性firstNamelastName这将在后台生成

- (void)setFirstName:(NSString *)aFirstName
{
    self.firstName = aFirstName;
}

- (NSString *)firstName
{ 
    // Note in objective-c we don't generally use `get`
    return self.firstName;
}

- (void)setLastName:(NSString *)aLastName
{
    self.lastName= aLastName;
}

- (NSString *)lastName
{ 
    // Note in objective-c we don't generally use `get`
    return self.lastName;
}

在与Java进行比较时,这与

相近
private String firstName;

public void setFirstName(String aFirstName) {
    this.firstName = aFirstName;
}

public String getFirstName() {
    return this.firstName;
}

我们创建实例变量的方式与我们执行它的方式相同,就好像它是一个普通的ivar但是没有什么可说的在java中创建我的setter和getter所以我们必须自己做。请注意,java中的ivar仍然是私有的,它是我们向其他人开放的getter和setter。


还有一种你错过的第三种选择。由于Objective-c中的约定,对于bool @property会发生什么?

我们声明它像

 @property (nonatomic) BOOL personForObject; 

在目标-c中,当涉及到bools时,吸气剂的名称略有不同。虽然我们对合成的

的制定者感到满意
- (void)setPersonForObject:(BOOL)aPersonForObject 
{
    self.personForObject = aPersonForObject;
}

我们对吸气剂感到不满意,当涉及到bools时,吸气剂应该从is开始,因此personForObject吸气剂应该是isPersonForObject但是合成不知道这样就会以另一种方式自动生成吸气剂。所以我们需要在属性声明中告诉它,如

@property (nonatomic, getter=isPersonForObject) BOOL personForObject;

您现在必须自己实现此方法,但需要

- (BOOL)isPersonForObject
{
    return self.personForObject;
}

请注意,只有在您选择忽略我不推荐的约定时才需要这样做。

任何问题都可以问。

答案 1 :(得分:0)

第二个代码相当于Java版本。

最完整版本中的@property定义了getter,setter和instance变量。您还可以修改声明以仅指定getter,仅指定setter或指定其他实例变量。

答案 2 :(得分:0)

@property是定义实例变量及其相应访问器的简写。 如果只是在接口中定义实例变量,则不会获得访问器方法。

答案 3 :(得分:0)

无论何时在Objective-C中声明成员,您都应该为这些成员提供getter和setter(Variables)。但Objective-C使用指令 @property @synthesize 支持名为合成访问者的内容。

现在让我们看看带有合成访问器的程序:

#import<Foundation/Foundation.h>
@interface Person : NSObject{
NSString * firstName;// declaring that Person class as variable firstName
NSString * lastName;// // declaring that Person class as variable lastName
}

@property NSString *firstName; // says to compiler that we want to define synthesized accesor for the firstName
@property NSString *lastName;// says to compiler that we want to define synthesized accesor for the lastName
@end

@implementation Person

@synthesize firstName, lastName;// synthesized accessor to be defined for firstName and lastName

@end;

int main(){
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc]init];
    Person * p = [[Person alloc]init] ;
    [p setFirstName:@"Yogish"]; // method setFirstName is implicitly defined by compiler
    [p setLastName:@"Gowda"];// method setLastName is implicitly defined by compiler
    NSLog(@"%@",p.firstName);
    NSLog(@"%@",p.lastName);
    [pool drain];
    return 0;

    }

现在回来如果你没有使用 @property @synthesize 你应该编写自己的setter和getters方法设置并获取成员firstName和lastName。由于您正在使用@property和@synthesize,编译器将编写getter和setter方法。

希望这会有所帮助:)