property之self.xx与_xx的区别

关于self.xx_xx,是同一个指针,只是前者调用该类的settergetter方法,后者直接获取自己的实例变量。即这个问题也就演变成了属性(property)和实例变量(instance variable)的区别了。

直接区别

  • 通过settergetter方法和通过实例变量的区别。

OC 2.0之后属性一旦声明,如果没有readonly修饰的话,当前类自动生成了settergetter方法的声明,并且会自动生成对应的实例变量(下划线+属性名)。而settergetter就是访问这个实例变量的方法。

在当前类的.m文件里直接用实例变量名来访问自身的实例变量的时候,settergetter方法是不会被调用。但是外部想用该类的实例变量就需要通过gettersetter方法了。

深层区别

  • 内存管理语义特性的区别

关于setter方法并不仅仅是将传入的参数直接赋值给实例变量,而是经过了一些简单的操作,下面是一个完整的 setter方法。

//属性例子
@property (nonatomic,retain)Person *person;

//setter
-(void)setPerson:(Person *)person
{  
	//判断当前传入的对象是否是已经持有的对象
    if (_person != person) {
        //释放之前的所有权
        [_person release];
        //操作 retain ,获取新的持有所有权
        _person = [person retain];
    }
}

很明显, 当属性的语义特性为retain或者copy的情况下,通过self.xx = **时,经过了 setter方法。这时实例变量会先释放,再进行 retain 或者 copy ,此时引用计数会+1,然后在赋值给实例变量。

  • 消息发送的区别

_xx 访问时,在编译期程序就已经知道它的内存地址了,运行时是直接通过偏移量这种硬编码方式访问变量的内存地址;用 self.xx 访问时,是在运行时通过消息机制动态的访问变量的。

_xx 的性能更好,但是会有一个隐患(这个隐患可能永远不会被触发),就是 OC 是非常动态的,你甚至可以在运行时添加成员变量,但是如果你添加的成员变量的内存地址在 _xx 的前面,那你用 _xx 这种硬编码的方式访问就必然会出错。

  • 键值观测触发的区别

另外,如果直接访问实例变量,将不会触发键值观测(KVO)的通知。这样做是否会产生问题,还取决于具体的对象行为。

关于->xx和_xx

也许你也曾见过在类的外部直接取成员变量的方式,如: instance->xx。_xx->xx 的方式其实都是直接取的成员变量,只是 -> 既可以用作类的内部也可以用做类的外部。下面举个例子,有这么一个TestA类:

@interface TestA : NSObject {
@public
    NSInteger _someIvar;
    NSString *_firstName;
    NSString *_lastName;
@private
    NSInteger _age;
}

- (void)methodForTestA;
@end

@implementation TestA

- (void)methodForTestA {
    self->_someIvar = 10;
    NSInteger age = self->_age;
}

@end

TestA的成员变量在外部的使用:

    TestA *testA = [[TestA alloc] init];
    testA->_firstName = @"赵钱孙李";
    NSInteger someValue = testA->_someIvar;

还有一些情况,最好不用使用self.xx,具体请查看:
在对象内部尽量直接访问实例变量

相关资料

属性详解(@property/@dynamic/@synthesize)
在对象内部尽量直接访问实例变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值