@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。