在OC中我们可以通过指令@property定义属性。

OC对属性封装了许多方法,同时也会自动实现一些方法,相比实例变量,感觉更加面向对象些。

一般定义属性的方法如下,在Class Test中定义属性int a。

@interface Test:NSObject
@property int a;
-(void) changeAValue:(int) newValue;
@end

在类的实例方法中,我们可以用下面两种方式来访问a属性:

1、直接用属性名访问:


-(void) changeAValue:(int) newValue
{
_a = newValue; // 默认生成的属性成员变量前面会自动加上“_”前缀
}

2、通过self.a的形式访问


-(void) changeAValue:(int) newValue
{
self.a = newValue;
}

这两种访问方式有区别吗?答案是肯定的。

通过第一种方式访问,其实是类似于C++的访问方式,是直接访问的实例变量并赋值。而第二种方式,并不像其表面那么直观,它其实是通过调用编译器自动生成的对于a变量的赋值函数来实现的。即

-(void) changeAValue:(int) newValue
{
self.a = newValue; // 此处实际是调用 [self setA:newValue];
}
 

个人感觉在类中调用自身的属性,还是用self.a的形式比较好。因为它封装了访问方法,加强了我们对变量的控制,也更面向对象些。

为了说明self.a的形式更好用一点,我们可以举个例子。在Class Test中,再添加对象属性NSString* b,并指明其为一个深拷贝属性。


@interface Test:NSObject
@property int a;
@property(copy) NSString* b, *c;
-(void) changeAValue:(int) newValue;
-(void) changeBValue:(NSString*) newBValue andCValue:(NSString*) newCValue;
@end

添加实例方法changeBValue:andCValue

-(void) changeBValue:(NSString*) newBValue andCValue:(NSString*) newCValue

{
self.b = newBValue; _c = newCValue;
}

在mian函数中写测试用例:

int main(int argc, const char * argv[]) {
@autoreleasepool { Test* testObj = [[Test alloc] init];
NSMutableString* newBValue = [NSMutableString stringWithString:@"Tom"];
NSMutableString* newCValue = [NSMutableString stringWithString:@"www3@126.com"];
[testObj setBValue:<span style="font-family: Arial, Helvetica, sans-serif;">newBValue </span>andCValue:newCValue]; NSLog(@"The value of b is %@ and c is %@", testObj.b, testObj.c);
[name appendString:@"andLily"];
[email appendString:@"andLily"];
NSLog(@"The value of b is %@ and c is %@", testObj.b, testObj.c); }
return 0;
}

运行,得到结果为

可以看到,b的值仍然是Tom,而c的值已经跟随这newCValue的值做了改变,末尾添加了“andLily”字符串。

我们的原意是对类属性的赋值应当是深拷贝赋值(在@property声明中添加了copy关键字),但现在b是深拷贝,而c仍然是默认的浅拷贝。究其原因,就是因为一个调用了self来访问,另一个直接对类属性进行了访问。在调用self的赋值方法访问时,编译器会自动根据copy关键字生成对应的深拷贝赋值函数,其实现类似于:

-(void) setB:NSString* newValue
{
if ( _b! = newValue)
{
_b = [newValue copy];
}
}

b已经和外部不指向同一块内存,因此b的值没有随着外部而改变。

从上面的例子可以看出,我们在类中,应该尽量使用self.a的形式来访问属性,这样对属性的访问会更加可靠简单,否则就需要我们自己实现对应属性的存取方法。

关于类的属性,还有下面几点要注意:

1、类的属性仅在本类中可以访问,子类无法通过_a的形式访问。但是可以通过继承父类的存取方法访问。

2、当声明类的属性后,编译器会自动生成对应的存取方法,但是我们仍然可以通过重写的方式,阻止编译器自动为我们生成存取方法,而是使用我们自己定义的存取方法。

self.a 和 _a 的区别的更多相关文章

  1. C语言数组和指针的理解_在取地址运算上的操作_指针加减操作_a 和&a 的区别

    1.一个实例+理论分析 在了解数组和指针的访问方式前提下,下面再看这个例子: main() { int a[5]={1,2,3,4,5}; int *ptr=(int *)(&a+1); pr ...

  2. Objective-C 中self.与_访问方式的区别

    Objective-C中属性self.a与_a访问的区别: 在OC中我们可以通过指令@property定义属性. OC对属性封装了许多方法,同时也会自动实现一些方法,相比实例变量,感觉更加面向对象些. ...

  3. c++ list, vector, map, set 区别与用法比较

    http://blog.csdn.net/alex_xhl/article/details/37692297 List封装了链表,Vector封装了数组, list和vector得最主要的区别在于ve ...

  4. Python第二天 变量 运算符与表达式 input()与raw_input()区别 字符编码 python转义符 字符串格式化 format函数字符串格式化 帮助

    Python第二天  变量  运算符与表达式  input()与raw_input()区别  字符编码  python转义符  字符串格式化  format函数字符串格式化  帮助 目录 Pychar ...

  5. iOS学习——@class和#import、#include的区别

    在iOS开发过程中,我们在一些源码中经常会看到导包的时候有的用#import进行导包,但是有的的时候也会看到用@class进行导包,那么这两种方式有什么区别呢? 一 @class和#import的主要 ...

  6. 【SQL】glob 和 like 的区别

    LIKE 和 GLOB 都可以用来匹配通配符指定模式的文本值.如果搜索表达式与模式表达式匹配,LIKE 运算符将返回真(true),也就是 1 区别: (1)使用的通配符不一样 like:  百分号( ...

  7. var和const和let的区别

    简述: 1.前端的变量申明,可以用到var,ES6的const(衡量)/let(变量) 2.在ES5用的都是var,到ES6之后,也就是2015年开始出现const/let. var 不会报错,有声明 ...

  8. C++浅拷贝和深拷贝的区别

    C++浅拷贝和深拷贝的区别 2012-04-24 21:22 11454人阅读 评论(6) 收藏 举报 c++deleteclass编译器c c++默认的拷贝构造函数是浅拷贝 浅拷贝就是对象的数据成员 ...

  9. list, vector, map, set 区别与用法比较

    List封装了链表,Vector封装了数组, list和vector得最主要的区别在于vector使用连续内存存储的,他支持[]运算符,而list是以链表形式实现的,不支持[]. Vector对于随机 ...

随机推荐

  1. SQL Server T-SQL高级查询(转)

    高级查询在数据库中用得是最频繁的,也是应用最广泛的.   Ø 基本常用查询   --select select * from student; --all 查询所有 select all sex fr ...

  2. 使用SE16N_INTERFACE

    调用函数直接修改table数据             在PRD上通常没有权限 但是可以激活sap内置的修改模式     SE16N 修改表数据.增加.删除行项目: 1. Execute tcode ...

  3. 萝卜家园32位和64位Win7系统Ghost版

    新萝卜家园32位Win7系统Ghost版Sp1,官方旗舰版采用Windows7 SP1简体中文旗舰版32位(MSDN官方发布正式版原版ios镜像)制作,并能够完美自动激活,采用自由天空驱动包,解决部分 ...

  4. centos -bash-4.1$ 不显示用户名路径

    1.在Terminal输入: vi ~/.bash_profile 2.如果没有.bash_profile可以自己添加.然后往文件中添加如下内容: export PS1=’[\u@\h \W]$ 注意 ...

  5. POJ C程序设计进阶 编程题#4:寻找平面上的极大点

    编程题#4:寻找平面上的极大点 来源: POJ (Coursera声明:在POJ上完成的习题将不会计入Coursera的最后成绩.) 注意: 总时间限制: 1000ms 内存限制: 65536kB 描 ...

  6. SVN 管理

    01. 源代码管理工具概述(PPT) ================================================================================ ...

  7. VS2010 /VC/bin/rcdll.dll 无法找到资源编译器

    把C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin 目录下的rcdll.dll拷贝到 C:\Program Files(x86)\Micr ...

  8. jquery源码学习--iceDog

    /** * @FileName : iceDog * @Author : PheonixHkbxoic * @Mail : hkbxoic@gmail.com * @DateTime : 2016-0 ...

  9. js对象与this指向

    创建对象的方法 1.对象字面量法 var obj={} var obj={ 'first-name':'Tom', 'last-name':'bush', age:24, Family:{ Broth ...

  10. java8新特性笔记

    1.forEach(),遍历数据结构中的元素,括号内可以带一个闭包的方法 2.双冒号用法:forEach(this::doSchedule),如果运行环境是闭包,java允许使用双冒号的写法来直接调用 ...