前言
苹果公司在Objective-C 2.0中引入了属性(property),它组合了新的预编译指令和新的属性访问器语法。新的属性功能显著减少代码的数量,帮助我们偷懒。
目标
利用属性访问器,知道怎么正确偷懒,美其名日:写出更优雅的代码。
内容
1.简化接口代码
使用@property
@property是让编译器自动产生函数申明。是一种编译器级别的偷懒技术。
@property就是编译器指令,就是让编译器自动声明getter和setter函数。
Dog.h 接口代码(本质代码哦):
@interface Dog:NSObject
{
int age;
}
- (void)setAge:(int)newAge;
- (int )age;
@end
1)类似于setAge:设置新值的函数一般叫做setter函数
2)类似于age:取值函数一般叫做getter函数
使用@property不用写下面2行代码:
- (void)setAge:(int)newAge;
- (int )age;
而用一行代码代替:
@property int age;
所以使用@property偷懒后的代码如下:
@interface Dog:NSObject
{
int age;
}
@property int age;
@end
2.简化实现代码
使用@synthesize来简化实现代码,@synthesize就是编译器指令,就是让编译器自动实现getter和setter函数。
Dog.m 实现代码(本质版本):
#import "Dog.h"
@implementation Dog
- (void) setAge:(int)newAge
{
age = newAge;
}
- (int)age
{
return age;
}
@end
使用@synthesize偷懒后的新版本:
@implementation Dog
@synthexize age;
@end
3.总结一下下
可以互换替换:
4.点语法
为什么要设计点语法?
- 为了方便别的程序员转到OC开发上来
- 为了让程序设计简单化(要会偷懒)
- 隐藏了内存管理细节
- 隐藏了多线程、同步、加锁细节
点语法
- 属性可以在不使用括号的情况下使用点语法
- [Car value]——》Car.value替换
虽然Car.value感觉是直接访问value变量,但属性始终是调用方法的,还是要通过这些方法来访问对象数据。
使用经典调用和点语法:
Dog *dog = [[Dog alloc] init];
[dog setAge:100];
int dogAge = [dog age];
NSLog(@"Dog Age is %d",dogAge);
dog.age = 200;
dogAge = dog.age;
NSLog(@"Dog new Age is %d",dogAge);
点语法也是编译器级别的。
dog.age = 200;
dogAge = dog.age;
编译器会把dog.age = 200;展开成(翻译成)
[dog setAge:200];
把dogAge = dog.age; 展开成(翻译成)
dogAge = [dog age];
类内部的age和self.age不是同一个东东:
- 在Dog类内部可以直接访问age变量
- 直接访问age相当于age字段
- self.age是调用getter或者setter函数
5. 属性的特性
使用属性参数,例如上面car属性的setter方法,可以通过@property定义如下:
@property (nonatomic,retain) Car *car;
你会发现此刻我们不必手动实现car的getter、setter方法程序仍然没有内存泄露。其实大家也应该都已经看到前面Person的name属性定义的时候我们同样加上了(nonatomic,copy)参数,这些参数到底是什么意思呢?
@property的参数分为三类,也就是说参数最多可以有三个,中间用逗号分隔,每类参数可以从上表三类参数中人选一个。如果不进行设置或者只设置其中一类参数,程序会使用三类中的各个默认参数,默认参数:(atomic,readwrite,assign)
一般情况下如果在多线程开发中一个属性可能会被两个及两个以上的线程同时访问,此时可以考虑atomic属性,否则建议使用nonatomic,不加锁,效率较高;readwirte方法会生成getter、setter两个方法,如果使用readonly则只生成getter方法;
关于set方法处理需要特别说明,假设我们定义一个属性a,这里列出三种方式的生成代码:
assign,用于基本数据类型
-(void)setA:(int)a{
_a=a;
}
retain,通常用于非字符串对象
-(void)setA:(Car *)a{
if(_a!=a){
[_a release];
_a=[a retain];
}
}
copy,通常用于字符串对象、block、NSArray、NSDictionary
-(void)setA:(NSString *)a{
if(_a!=a){
[_a release];
_a=[a copy];
}
}
备注:本文基于MRC进行介绍,ARC下的情况不同,请参阅其他文章,例如ARC下基本数据类型默认的属性参数为(atomic,readwrite,assign),对象类型默认的属性参数为(atomic,readwrite,strong)
总结+废话
- 两个编译器指令:@property,@synthesize的作用。
- 一个编译器语法:点语法。
- 一堆属性参数(特性)。