@property实际上在幕后做了些什么? 和自我>和_下划线

我还在挣扎@implementation部分的语法错误。

所以,我想了解使用@property而不是。

第一种情况是一个@interface,我在{}中声明了一些variables。

//ViewController.h #import <UIKit/UIKit.h> #import "Student.h" // just class i made @interface ViewController : UIViewController { Student *stObj; } 

而且,我试图引用stObj指针使用几个标识符(_(下划线),self。,self>,没有)

 // ViewController.m #import "ViewController.h" @interface ViewController () // just leaving this code cuz i haven't study what it is :) @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; stObj = [[Student alloc]init ]; //no error //self->stObj = [[Student alloc]init]; //no error //self.stObj = [[Student alloc]init]; //error! //_stObj = [[Student alloc]init]; //error! } 

第二种情况是@interface,我使用@property

 @interface ViewController : UIViewController @property Student *stObj; @end 

并做同样的事情,如上所述。

 stObj = [[Student alloc]init ]; //error //self->stObj = [[Student alloc]init]; //error //self.stObj = [[Student alloc]init]; //no error! //_stObj = [[Student alloc]init]; //no error! 

所以,你可以看到我不得不假设的是自我。 和_(下划线)工作,似乎相似…?

问题是,什么@属性实际上造成不同的结果..?

感谢您阅读我的问题,如果我做错了,请纠正我。


首先,让我们来解释一下属性是什么:它基本上是一组方法,通常用于访问一个实例variables。 这是一个过于简单(稍微不正确)的解释,但大部分时间都足够了。

您可以使用@synthesize关键字来定义实例variables的名称,如下所示:

 @property Type foo; ... @synthesize foo = somethingElse; 

在这种情况下,编译器将生成:

  • 一个名为somethingElse的types为Type的实例variables。
  • 读取名为foo的variables的方法:它只返回variablessomethingElse的内容。
  • 写一个名为setFoo:variables的方法:它设置variablessomethingElse的内容,并负责通知键值观察者。

如果不指定@synthesize语句,编译器将自动生成一个实例variables,其属性名称前面加下划线。 所以如果你的属性被命名为foo ,那么自动创build的实例variables被称为_foo

当你这样做时:

 @property Student *stObj; 

(没有@synthesize )编译器生成:

  • Student *types的实例variables_stObj
  • 一个名为stObj的方法,用于读取variables_stObj的内容。
  • 一个名为setStObj:的方法setStObj:写入variables_stObj的内容。

接下来,访问实例variables:如果范围允许(如_foo ),则可以直接访问它们的名称,也可以像在self->_foo那样通过-> dereference运算符来访问它们。 后者还允许您访问其他对象的公共实例variables,如在otherObject->_foo 。 不过,除非你真的知道你在做什么,否则不要这样做。

最后但并非最不重要的是点符号。 写obj.method与写[obj method] ,写obj.method = value与写[obj setMethod:value] 。 也就是说,点符号是方法调用的较短的语法。 (我倾向于避免它,因为它也是访问struct成员的符号,但这只是我。)

有了这些知识,你的例子很容易解释:

在你的第一个例子中:

 stObj = [[Student alloc] init]; // Access to instance variable. OK. self->stObj = [[Student alloc]init]; // Access to instance variable. OK // The next statement is the same as [self setStObj:[[Student alloc]init]; // But there is no method named setStObj: defined. self.stObj = [[Student alloc]init]; // Trying to access a variable that doesn't exist. It's called stObj instead. _stObj = [[Student alloc]init]; 

在你的第二个例子中:

 // There is no variable stObj, it's called _stObj in this case. stObj = [[Student alloc]init ]; // That's why this fails. self->stObj = [[Student alloc]init]; // And this as well. // The property has created the `setStObj:` method, so the next // line succeeds. self.stObj = [[Student alloc]init]; // The property has created the _stObj instance variable, so the // next line succeeds. _stObj = [[Student alloc]init]; 

@property自动为实例variables实现访问器(如果没有指定,甚至会创build实例variables)。 所以@property Student *stObj; 是等价的定义和实现-(Student *)stObj;-(void)setStObj:(Student*)student;

stdObj = …失败的原因是默认variables名称是一个带有下划线前缀的属性,所以_stdObj = …将起作用。

不同之处在于@property不是一个实例variables; 相反,它是一个实例variables的getter / setter。

当与属性一起使用时,点语法将调用(void)setObject:(id)object(id)object方法 – 底层实例variables的访问器/增变器。 默认情况下,底层实例variables是以下划线作为前缀的属性名 – 这就是为什么您通常不需要@synthesize stdObj = _stdObj因为这是默认行为。

考虑到这一点,如果你要声明一个简单的iVar, self.stdObj将是非法的,除非你为那个iVar声明了一个getter / setter(或者把它作为一个属性)。 self->stdObj直接访问iVar。