what does @property actually do behind the scene..

2020-02-15 04:00发布

I'm still struggling with the syntax errors in @implementation section.

So, I want to understand the difference between using @property and not.

First case is would be one @interface where i declared some variable in {}.

//ViewController.h


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

@interface ViewController : UIViewController
{
    Student *stObj;
}

And, i'm trying to refer to stObj pointer using several identifier ( _(underscore), self. , self->, nothing)

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



 }

Second case is would be one @interface where i use @property

@interface ViewController : UIViewController

@property Student *stObj;

@end

and do the same thing like above.

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

SO, as you can see what i had to assume was that self. and _ (underscore) worked and seems similar ...?

The Question is that what @property actually does causing different result..?

Thank you for reading my question and if i'm doing something wrong please correct me.


3条回答
冷血范
2楼-- · 2020-02-15 04:09

First, let's explain what a property is: it's basically a set of methods, usually for accessing an instance variable. That's an overly simple (and slightly incorrect) explanation but it will suffice most of the time.

You can define the name of the instance variable with the @synthesize keyword, as in:

@property Type foo;

...

@synthesize foo = somethingElse;

In this case, the compiler will generate:

  • An instance variable called somethingElse of type Type.
  • A method to read the variable called foo: it just returns the content of the variable somethingElse.
  • A method to write the variable called setFoo:: it sets the content of the variable somethingElse and takes care of notifying key-value observers.

If you don't specify a @synthesize statement, the compiler will automatically generate an instance variable with the property name prefixed by an underscore. So if your property is named foo, the automatically created instance variable is called _foo.

When you do:

@property Student *stObj;

(without a @synthesize) the compiler generates:

  • An instance variable _stObj of type Student *.
  • A method called stObj that reads the content of the variable _stObj.
  • A method called setStObj: that writes the content of the variable _stObj.

Next, access to instance variables: you can either access them by their name directly, if the scope allows it (like _foo), or you can access them via the -> dereference operator as in self->_foo. The later also allows you to access public instance variables of other objects, as in otherObject->_foo. Don't do this unless you really know what you're doing, though.

Last but not least, the dot-notation. Writing obj.method is the same as writing [obj method] and writing obj.method = value is the same as writing [obj setMethod:value]. That is, the dot-notation is a shorter syntax for a method call. (I tend to avoid it since it's also the notation for access struct members, but that's just me.)

With that knowledge, your examples are easy to explain:

In your first example:

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

In your second example:

// 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];
查看更多
叼着烟拽天下
3楼-- · 2020-02-15 04:11

@property automatically implements accessors for the instance variable (and will even create the instance variable if none is specified). So @property Student *stObj; is the equivalent och defining and implementing -(Student *)stObj; and -(void)setStObj:(Student*)student;.

The reason that stdObj = … fails is that the default variable name is the property named prefixed with an underscore, so _stdObj = … will work.

查看更多
ら.Afraid
4楼-- · 2020-02-15 04:27

The difference is that a @property is not an instance variable; rather, it is the getter/setter for an instance variable.

When used with properties, dot syntax will call the (void)setObject:(id)object and (id)object methods -- the accessor/mutator for the underlying instance variable. By default, the underlying instance variable is the property name prefixed by an underscore -- this is why you typically don't need @synthesize stdObj = _stdObj because that is the default behavior.

With that in mind, if you were to declare a simple iVar, self.stdObj would be illegal unless you declared a getter/setter for that iVar (or made it a property). self->stdObj directly accesses the iVar.

查看更多
登录 后发表回答