@property实际上在幕后做了什么......使用自我。和自我>和_下划线

时间:2014-03-14 07:24:02

标签: ios objective-c properties

我仍然在努力解决@implementation部分中的语法错误。

所以,我想了解使用@property与否之间的区别。

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

//ViewController.h


#import <UIKit/UIKit.h>
#import "Student.h"       // just class i made

@interface ViewController : UIViewController
{
    Student *stObj;
}

并且,我正在尝试使用多个标识符(_(下划线),self。,self-&gt;,无)来引用stObj指针。

//  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!

所以,你可以看到我必须假设的是那个自我。和_(下划线)有效并且看似相似......?

问题是@property实际上导致不同结果的内容..?

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


3 个答案:

答案 0 :(得分:5)

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

您可以使用@synthesize关键字定义实例变量的名称,如:

@property Type foo;

...

@synthesize foo = somethingElse;

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

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

如果您没有指定@synthesize语句,编译器将自动生成一个实例变量,其属性名称以下划线为前缀。因此,如果您的属性名为foo,则自动创建的实例变量称为_foo

当你这样做时:

@property Student *stObj;

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

  • 类型为_stObj的实例变量Student *
  • 一种名为stObj的方法,用于读取变量_stObj的内容。
  • 一种名为setStObj:的方法,用于写入变量_stObj的内容。

接下来,访问实例变量:您可以直接通过名称访问它们,如果范围允许(例如_foo),或者您可以通过->取消引用运算符访问它们,如self->_foo。后者还允许您访问其他对象的公共实例变量,如otherObject->_foo中所示。不要这样做,除非你真的知道你正在做什么。

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

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

在你的第一个例子中:

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];

答案 1 :(得分:0)

@property自动为实例变量实现访问器(如果没有指定实例变量,甚至会创建实例变量)。因此@property Student *stObj;等同于定义和实施-(Student *)stObj;-(void)setStObj:(Student*)student;

stdObj = …失败的原因是默认变量名是名为前缀为下划线的属性,因此_stdObj = …将起作用。

答案 2 :(得分:0)

区别在于@property不是实例变量;相反,它是实例变量的getter / setter。

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

考虑到这一点,如果您要声明一个简单的iVar,self.stdObj非法,除非您为该iVar声明了一个getter / setter(或使其成为属性)。 self->stdObj直接访问iVar。