OC中self.a和_a的访问的区别

扬帆起航

久了不回顾基础知识,猛然间看到,有时候还真想不起来有的知识,比如声明@property和合成@synthesize的属性与普通的属性有什么本质区别,self.a和_a访问的区别,所以有必要回顾一下。


我们先来说说@property和@synthesize
@property声明成员变量,会自动帮我们生成该成员变量的getter/setter方法的声明;
@synthesize的作用是自动生成成员变量的getter/setter方法的定义;
所有被声明为属性的成员,在iOS5 之前需要使用编译器指令@synthesize 来告诉编译器帮助生成属性的getter,setter方法。之后这个指令可以不用人为指定了,默认情况下编译器会帮我们生成。
这里先浅显的说明@property和synthesize的作用,其他的知识自己google,今天主要回顾self.a和_a的区别。


首先使用self.a会调用getter/setter方法,而_a并不会调用getter/setter方法,它是直接访问实例变量并赋值。
下面我们通过@property的copy属性举例说明:

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property (nonatomic, copy) NSString *name;
@property (nonatomic, copy) NSString *sex;

- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue;

@end

上面是一个Person类,里面有两个成员变量name和sex,声明了一个实例方法changeNameValue:andChangeSexValue:,下面实例方法的实现:

#import "Person.h"

@implementation Person

- (void)changeNameValue:(NSString *)newName andChangeSexValue:(NSString *)sexValue
{
    self.name = newName;
    _sex = sexValue;
}

@end

然后在viewDidLoad方法中调用:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    NSMutableString *newName =[NSMutableString stringWithString:@"TongRy"];
    NSMutableString *newSex = [NSMutableString stringWithString:@"man"];
    
    Person *xiaoming = [[Person alloc] init];
    [xiaoming changeNameValue:newName andChangeSexValue:newSex];
    
    NSLog(@"xiaoming newName: %@, newSex: %@;", xiaoming.name, xiaoming.sex);
    
    [newName appendString:@"Good"];
    [newSex appendString:@"andwoman"];
    NSLog(@"To observe the changes : xiaoming name: %@, sex: %@;", xiaoming.name, xiaoming.sex);
    
}

运行后得到的结果:


运行结果

我们可以看到,newName和newSex改变了,name的值仍然没有变是TongRy,而sex的值确是改变了,末尾增加了“andwoman”.

实际上我们期待的是对类属性的赋值是深拷贝赋值(我们声明了@property的copy属性),但是实际得到的结果是name进行了深拷贝,而sex仍然是浅拷贝。究其原因,就是因为name是self访问,sex是_访问。在调用self的时候,如果是赋值,那么编译器会自动根据strong/copy生成对应的setter方法,其实现类似于:

//声明为copy属性时
- (void)setName:(NSString *)name
{
    if (_name != name)
    {
        [_name release];
        _name = [name copy];
    }
}

//当声明为retain属性时(MRC下)
- (void)setName:(NSString *)name
{
    if (_name != name)
    {
        [_name release];
        [name retain];
        _name = name;
    }
}

在上面的例子中,使用self.name赋值后,name已经和newName没有指向同一块内存,所以name没有随着newName值的改变而改变。_sex赋值是直接指向了newSex所指向的内存块,也没有做retain操作,容易出现问题。所以,我们在类中应该尽量使用self.a的形式来访问属性。

用self.name 是更好的选择,因为这样可以兼容懒加载,同时也避免了使用下划线的时候忽视了self这个指针,后者容易在block中造成循环引用。同时,使用_是获取不到父类的属性,因为它只是对局部变量的访问。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 年去年来岁月稠, 光阴似箭不能留。 青山有梦古今望, 绿水含情日夜流。 尘世难逢开口笑, 诗肠总断别时愁。 幸喜人...
    高湛明阅读 359评论 3 8
  • 我不知道。现在的一切都很混乱。 我内心有深深的无力感和挫败感,觉得自己不行。
    BelovedNutan阅读 283评论 0 0
  • 上个月买了一本《目送》,从龙老师的笔下,更多的流露出对亲情的真挚。 “我慢慢地、慢慢地了解到,所谓父女母子一场,只...
    陪月亮摘星星阅读 677评论 0 6
  • 午夜的街道,街灯、穿梭的汽车和雾气笼罩的街道。这是11月底的一天,她又是最晚离开公司的那一个。风很大,北方冬天的大...
    苏峰001阅读 225评论 4 0

友情链接更多精彩内容