很多人讲属性修饰词的时候,喜欢从字面或者定义的角度介绍它们间的区别。这篇文章,我们侧重从修饰词对setter方法的影响直接展示区别。
_
作为实例变量名字的前缀,如_student
@interface Person : NSObject {...}
这样的花括号{...}
里面@interface Person ()<UIScrollViewDelegate> {...}
这样的花括号{...}
里面@interface TYPagerController ()<UIScrollViewDelegate> {
NSInteger _countOfControllers;
BOOL _needLayoutContentView;
CGFloat _preOffsetX;
float _heightInMeters;
struct {
unsigned int transitionFromIndexToIndex :1;
unsigned int transitionFromIndexToIndexProgress :1;
}_delegateFlags;
struct {
unsigned int transitionFromIndexToIndex :1;
unsigned int transitionFromIndexToIndexProgress :1;
}_methodFlags;
}
可以自己手动为实例变量在头文件 中声明setter、getter方法,并在实现文件中实现setter、getter方法。你也可以不声明不实现,但不要再企图调用setter、getter方法了,甚至点语法。
//一个例子
//实现getter
- (float)heightInMeters{
return _heightInMeters;
}
//实现setter
- (float)setHeightInMeters:(float)h{
_heightInMeters = h;
}
如果你实现了setter,getter方法,才可以调用存取方法,例如:
//调用getter
float temp = [self heightInMeters];
//调用setter
[self setHeightInMeters:10.0];
如果你实现了setter,getter方法,才可以使用点语法 简化调用存取方法。
//调用getter
float temp = self.heightInMeters;
//调用setter
self.heightInMeters = 10.0;
int _sudentNum;
,float _heightInMeters;
这种实例变量及其值会在声明对象的内部保存。
NSString *tempStr
,CMPersonModel *personModel
等等。这种属性叫对象实例变量。这种变量,声明的对象内部仅保存指向相应实例对象的指针(对象地址),而不保存实例对象本身。实例对象本身由堆负责保存,管理机制由ARC负责。
{...}
之外#import <UIKit/UIKit.h>
@interface TMAddCategoryViewController ()
@property (nonatomic, strong) NSMutableArray *dataSource;
@end
- (NSMutableArray *)dataSource
{
if (!_dataSource) {
_dataSource = [NSMutableArray array];
RLMResults *results = [[TMDataBaseManager defaultManager] queryAddCategorysWithPaymentType:self.paymentType];
for (TMAddCategory *category in results) {
[_dataSource addObject:category];
}
}
return _dataSource;
}
注:RLMResults是第三方数据库框架Realm中的一个类名
- (void)setDataSource:(id<iCarouselDataSource>)dataSource
{
if (_dataSource != dataSource)
{
_dataSource = dataSource;
if (_dataSource)
{
[self reloadData];
}
}
}
@property声明的属性,编译器是否会合成存取方法和成员变量有如下三种特别情况
@property(getter=isMarried)BOOL married;
通常BOOL类型的属性的getter方法要以is开头
修饰词:告诉编译器是否或怎样自动给属性生成存取方法
@property有两个对应的修饰词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
。 显然,这两个修饰的功能是互斥的。
@dynamic或者@synthesize,写在.m文件的@implementation中。
理解这两个修饰词的功能,可以先看看这两个单词的意思。
单词混淆: 多线程的概念里面有个关键词@synchronized跟@synthesize容易视觉混淆,这里也看看两个单词的意思。
定义属性后,编译器会自动编写访问这些属性所需的方法,此过程叫做自动合成 (autosynthesis)。需要强调的是,这个过程由编译器在编译期执行,所以编辑器里看不到这些“合成方法”(synthesized method)的源代码。除了生成方法代码 getter、setter 之外,编译器还要自动向类中添加适当类型的实例变量,并且在属性名前面加下划线,以此作为实例变量的名字。
@synthesize name = realName;
对于上面的实例变量则为生成的是realName而不是name,方法也对应改变。定义的实例变量是根据@synthesize name = realName;
来定的。用的比较多的情况是:
@synthesize name = _name;
上述代码的意思是,在@property 声明的name,在setter/getter
方法中使用NSObject * _name;
这个实例变量来赋值与返回。
@synthesize age = _age;
@synthesize age;//等效下面
@synthesize age = age;
当你在子类中重载了父类中的属性,你必须使用@synthesize来手动合成实例变量。
很多人讲这些修饰词的时候,喜欢从字面或者定义的角度介绍它们间的区别。这篇文章,我们从修饰词对setter方法的影响直接展示区别。
retain、assign、copy、weak、strong、nonatomic、atomic、readonly、readwrite
假设为了修饰一个属性nameStr,代码如下:
#import <UIKit/UIKit.h>
@interface CMViewController ()
@property (nonatomic, strong) NSString *nameStr;
@end
其中,当括号内的修饰词(nonatomic, strong)换成下面各种修饰词的时候,分别分析一下setter方法(有些修饰词修饰字符串并不合适,但这里仅为分析区别)。
- (void) setName:(NSString *)newValue{
nameStr = newValue;
}
- (void) setName:(NSString *)newValue{
if (nameStr !=newValue){
[nameStr release]
nameStr = [newValue retain];
}
}
- (void) setName:(NSString *)newValue{
if (nameStr !=newValue){
[nameStr release]
nameStr = [newValue copy];
}
}
copy的使用场景为,实现了NSCopying protocol的类,我想获取它的值,但是我又不想在原对象上改变,于是深赋值一份新的值给你,让你来自由操作。
weak、strong是ARC出现后才出现的概念,但这并不代表weak、strong这两个修饰都不能在MRC模式下使用。事实上,strong在MRC模式依旧可使用。
@property (nonatomic, weak) id delegate; // 修饰代理属性
[nameStr release]
nameStr = newValue;
strong 用来修饰强引用的属性,类似于对应原来的retain。
NSString *name = self.nameField.text; // 等价
__strong NSString *name = self.nameField.text; // 等价
[newValue retain]
[nameStr release]
nameStr = newValue;
读写性修饰符——readwrite、readonly
@property (nonatomic, readonly) CGFloat itemWidth;
@property (nonatomic, assign) double brightness;
@property (nonatomic, assign, getter=isOpenMenu) BOOL openMenu;
@property (nonatomic, strong) UILabel *newsBooksLabel;
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, weak) IBOutlet UIButton *nextButton;
@property (nonatomic, copy) void (^cancelBtnBlock)();
@property (nonatomic, weak) id<TMSideCellDelegate> sideCellDelegate;