Objective-C中类的成员变量与属性
在objective-c的类与对象的概念中. 成员变量与属性的区别与联系一直没有搞清楚. 直到学习了慕课网上的这个课程objective-c面向对象初体验, 才算真正有了点感觉了. 最关键的结论就是: 类内使用成员变量{}, 类外使用属性@property.
成员变量
成员变量及其get方法.
首先, 我们来看下基本的类成员变量及其使用.
// people.h @interface people : nsobject { nsstring *_peoplename; } @end
在.m中不做任何事情, 然后在main.m调用_peoplename成员变量,
(下图可以看出, 调用类的成员变量时, 使用 . 语法符号会出错, 必须使用->来调用):
调用类成员变量 title=>
改为->, 调用p1->_peoplename的结果如下:
即, 该_peoplename默认是protected, 外部调用需要设置为@public. 改动一下:喎?https: www.2cto.com/kf/ware/vc/"="" target="_blank" class="keylink">vcd4ncjxwcmugy2xhc3m9"brush:java;">
// people.h
@interface people : nsobject
{
@public
nsstring *_peoplename;
}
@end
调用p1->_peoplename的结果如下:
2015-05-06 15:58:41.039 memberandproperty[2851:304100] p1._peoplename : (null)
类内部使用成员变量
如果想在init中初始化_peoplename, 则在people.m中:
// people.m - (instancetype)init { self = [super init]; if (self) { _peoplename = @people name 1; } return self; }
调用p1->_peoplename的结果如下:
2015-05-06 16:01:36.974 memberandproperty[2895:306281] p1._peoplename : people name 1
其他使用该成员变量的类内部方法都是类似的用法.
set方法
以上是对类成员变量_peoplename的调用, 如果想要对其附新值呢?
// main.m people *p1 = [[people alloc] init]; nslog(@p1._peoplename : %@, p1->_peoplename); p1->_peoplename = @people name 2; nslog(@p1._peoplename : %@, p1->_peoplename);
结果:
2015-05-06 16:05:34.915 memberandproperty[2931:309406] p1._peoplename : people name 1 2015-05-06 16:05:34.916 memberandproperty[2931:309406] p1._peoplename : people name 2
以上可见, 将_peoplename设置为@public之后, 可在类外对其进行get/set操作, 直接调用或赋值即可.
但不推荐使用p1->_peoplename这样的形式. 因为, 这样就不符合我们所说的
“类内使用成员变量{}, 类外使用属性@property“的结论了. 且将成员变量_peoplename设为@public会很不安全.
自定义成员变量的get/set方法
仍然将成员变量_peoplename默认为@protected, 从类内部的方法中对_peoplename进行读取或赋值, 然后间接传递至类外部, 是一个不错的选择.
首先, 在.h中声明getname和setname方法:
// people.h @interface people : nsobject { nsstring *_peoplename; } -(nsstring *)getname; -(void)setname:(nsstring *)name; @end
在.m中, get/set这两个方法是以在类内部对成员变量_peoplename进行调用或赋值的方式来实现的.
// people.m -(nsstring *)getname { return _peoplename; } -(void)setname:(nsstring *)name { _peoplename = name; }
那么, 调用的时候就非常方便了:
// main.m people *p1 = [[people alloc] init]; nslog(@p1.getname : %@, p1.getname); [p1 setname:@people name 2]; nslog(@p1.getname : %@, p1.getname);
结果如下:
2015-05-06 16:25:36.019 memberandproperty[3036:320317] p1.getname : people name 1 2015-05-06 16:25:36.020 memberandproperty[3036:320317] p1.getname : people name 2
使用自定义的get/set, 从类内部调用成员变量是一种比较常见的方式. 但需手动添加这两个方法.
属性
那么, 有没有更加简便的方法呢? 或者说, get/set这种非常常见的操作, 能不能默认提供给我们呢? 答案是肯定的!
在新的ios sdk中, 使用@property来定义类的属性, 是专用于从类外部对其进行调用或赋值的.
在.h中先声明peoplename属性:
// people.h @interface people : nsobject { nsstring *_peoplename; } @property(nonatomic, strong) nsstring *peoplename; // nonatomic 非原子性访问, 不加同步机制, 多线程并非访问时可提高性能 // strong 相当于一个深拷贝的操作 @end
在.m中使用@synthesize指令将peoplename属性与_peoplename成员变量关联起来:
// people.m @implementation people @synthesize peoplename = _peoplename; - (instancetype)init { self = [super init]; if (self) { _peoplename = @people name 1; } return self; } @end
即, 编译器遇到@synthesize peoplename = _peoplename;时, 会自动生成对peoplename的get/set方法.
且这里的下划线_是必不可少的, 否则就不能正确地将属性与成员变量关联起来.
然后, 我们直接调用即可:
// main.m people *p1 = [[people alloc] init]; nslog(@p1.peoplename : %@, p1.peoplename); p1.peoplename = @people name 2; nslog(@p1.peoplename : %@, p1.peoplename);
结果如下:
2015-05-06 16:32:29.142 memberandproperty[3094:325295] p1.peoplename : people name 1 2015-05-06 16:32:29.143 memberandproperty[3094:325295] p1.peoplename : people name 2
实际上, 编译器比我们想象中更聪明, 在.h文件中的{ nsstring *_peoplename; }这个成员变量不需要声明也可以. 仅仅声明了@property(nonatomic, strong) nsstring *peoplename;这个属性, xcode也会默认自动为我们声明一个该类的peoplename成员变量, 及隐藏的get/set方法. 这里, 就体现出了下划线 的作用了.