我仍然在努力解决@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实际上导致不同结果的内容..?
感谢您阅读我的问题,如果我做错了,请纠正我。
答案 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。