在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. hdu2067

    如果i==j&&j-1>=0时候,f[i][j]=f[i][j-1]; 如果j==0时候,f[i][j]=1; 其他 f[i][j]=f[i-1][j]+f[i][j-1]; # ...

  2. Android IOS WebRTC 音视频开发总结(四八)-- 从商业和技术的角度看视频行业的机会

    本文主要从不同角度介绍视频行业的机会,文章来自博客园RTC.Blacker,支持原创,转载必须说明出处,欢迎关注个人微信公众号blacker ----------------------------- ...

  3. javaSE第二十三天

    第二十三天    338 1.进程和线程的概述    338 2.多线程(理解)    339 (1)多线程:一个应用程序有多条执行路径    339 (2)Java程序的运行原理及JVM的启动是多线 ...

  4. CentOS6.5 python 2.6升级到2.7

    在CentOS6.5下,将自带的python2.6.6升级到python2.7.3,解决方法如下: 下载python2.7.3包,并解压缩,输入命令:#wget http://python.org/f ...

  5. 取得Android平台某设备上所有可用的Sensors

    本来要写一个检测手机的温度的小应用,学习一下传感器的api,可结果怎么写不行.经检测,发现取得的Sensor为NULL,这才明白,我手机没有TYPE_AMBIENT_TEMPERATURE传感器. 于 ...

  6. MySQL连接语法

    http://www.cnblogs.com/hanzhaoxin/p/3590642.html 内连接:INNER  JOIN 内连接为 两个表中必须都同时满足条件 内连接,即最常见的等值连接自然连 ...

  7. PHP用Array模拟枚举

    C#中枚举Enum的写法: /// <summary> /// 公开类型 2-好友可见 1-公开 0-不公开 /// </summary> public enum OpenSt ...

  8. PHP preg_replace() 正则替换所有符合条件的字符串示例

    PHP preg_replace() 正则替换,与Javascript 正则替换不同,PHP preg_replace() 默认就是替换所有符号匹配条件的元素.  需要用程序处理的数据并不总是预先以数 ...

  9. C语言-sizeof()与strlen()的区别【转】

    先看看sizeof() 一.sizeof的概念 sizeof是C语言的一种单目操作符,如C语言的其他操作符++.--等.它并不是函数.sizeof操作符以字节形式给出了其操作数的存储大小.操作数可以是 ...

  10. Treeview获取父节点

    private void treeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object&g ...