实例变量和属性是两个不同的概念, 属性是iOS5之后新增的概念,属性的正常使用依附于实例变量
1,实例变量
1.1,定义形式
{
float privateVariable1;
NSString *privateVariable2;
}
1.2 访问权限类型
访问权限共四种:
@package 在包内是可以访问的
@public 公开的,不管在哪里都可以访问
@protected 受保护的, 能在当前类及其子类中访问, 默认情况下如果实例变量没有声明访问类型就是这种
@private 私有的, 只有在当前类中才能访问
以上情况是默认实例变量定义在.h 文件中的, 如果定义在.m文件中, 无论修饰符是什么外部都不能访问,相当于private
1.3内存管理策略
共四中__strong、__weak、__unsafe_unretained和__autoreleasing。
__strong修饰符
__strong修饰符是id类型和对象类型默认的所有权修饰符。
__strong修饰符表示对对象的“强引用”。持有强引用的变量在超出其作用域时被废弃,随着强引用的失效,引用的对象会随之释放,引用计数减1。
__weak修饰符
__strong修饰符修饰的变量表示强引用,意味着只要还有一个强引用存在,对象就不可能释放,但是有一个问题就是两个对象互相强引用,就会造成循环引用,__weak表示的是弱引用, 弱引用对对象的生命周期不会产生影响,并且当对象销毁时,__weak修饰的变量会自动设置为nil。所以可以用__weak修饰的变量是否为nil来判断对象是否已经被销毁。
__unsafe_unretained
顾名思义,它是不安全的, 和__weak相似但是有区别,相同点就是不会对对象的生命周期产生影响, 不会影响对象的引用计数,但是它是不安全的,当对象被销毁时,它不会自动设置为nil, 还是原来对象的地址。如果这个时候访问变量就会报野指针错误,所以使用的时候一定要确保对象存在。
__autoreleasing
用__autoreleasing修饰的变量的作用等同于ARC无效时调用autorelease方法,都是起到延时释放的作用。ARC有效时,用@autoreleasepool块替代NSAutoreleasePool类,用附有__autoreleasing修饰符的变量代替autorelease方法
1.4访问 和赋值
对于在当前类或者其子类内部, 有两种方式拿到实例变量: 可以直接使用实例变量名 或者 self->实例变量名进行取值和赋值
variable1 = @"asdfasdf";
self->variable2 = 123.1;
对于在外部访问实例变量时,只能使用对象->实例变量名
JTNewClassTest *asdf = [JTNewClassTest new];
asdf->variable1 = @"新赋值";
NSLog(@"%@",asdf->variable1);
2 属性
2.1,定义形式
@property (可变参数列表) BOOL property1;
可变参数列表中有四种类型的参数
* 原子属性 有atomic和nonatomic两种类型,其中默认是atomic类型,原子的 线程安全的
* 读写属性 默认是可读写的 当然可以readonly 和 readwrite 两种,默认是readwrite可读写的
* setter 或者 getter方法名, 默认情况下 如果没有指定,set方法名就是set属性名, get方法就是get属性名, 当然可以另外指定方法名
* 内存管理策略:
** strong, weak, assign, retain, copy,unsafe_unretained
其中strong、retain和copy对应__strong,修饰对象类型,表示强引用。
weak对应__weak 表示弱引用。assign和unsafe_unretained都对应__unsafe_unretained, 其中assign修饰基本数据类型,unsafe_unretained一般修饰对象类型,但是不安全的,使用的时候要确保对象存在。
用@property声明的属性默认情况下回自动生成名为_属性名的实例变量,和setter和getter方法
2.2 不要自己实现属性的setter和getter方法,因为 系统检测到你实现了setget方法就不会自动生成实例变量,,所以如果想自己实现就实现两个方法再添加一个实例变量
@property (nonatomic,assign)BOOL property1;
- (void)setProperty1:(BOOL)property1{
_property1 = property1;
}
- (BOOL)property1{
return _property1;
}
这种情况下 编译会报错,提示找不到实例变量_property1
2.3@synthesize 的作用
synthesize是合成的意思属性绑定 指定属性对应的实例变量的名字
@property 和 @synthesize在Xcode4.4以前一直都是配合着使用,在4.4以后,@property得到了增强,一行代码编译器就会自动帮我们生成setter和 getter方法的声明和实现,同时在.m文件中声明一个和属性名一样并且在最前面带有下划线的成员变量 (private)
@synthesize 属性名; 会生成和属性同名的实例变量,当然可以指定实例变量的名字。
@synthesize 属性名 = 实例变量名; 指定属性和对应的实例变量名
2.4 不会生成实例变量和getter setter方法的情况
* 同时实现setter、getter方法的时候,系统不会再合成ivar 和setter 、getter(当然只读属性,重写getter方法)
* 使用@dynamic propertyname的时候
* protocol 中定义的属性,不会自动合成setter、getter方法实现,只会生成声明
* category 中的属性,会生成getter setter 方法,但是并不会生成ivar,所以需要我们利用runtime objc_setAssociatedObject 和 objc_getAssociatedObject 绑定实例变量和获取实例变量
* 重载的属性不会生成
@dynamic关键字就要告诉编译器,对应属性的set和get方法以及实例变量会有的,编译的时候可以忽略
3,属性和实例变量的区别
访问属性的本质是调用属性的set和get方法。访问实例变量的本质是计算偏移量然后直接在内存中读取数据。所以存取方法有区别导致效率也有区别
3.1 实例变量访问效率要比属性高。
3.2 实例变量不能触发KVO, 属性能触发。
3.3 属性比较方便调试。
那么我们在开发中到底是用属性还是用实例变量呢? 这个分情况,在初始化和析构方法中最好用实例变量,其他都可以使用属性来实现访问了,除了在属性的set和get方法中(不然会循环调用)
4,copy修饰符,为什么NSString要用copy修饰呢?
4.1如果用strong修饰,NSMutableString是NSString 的子类, 如果给NSString属性赋值NSMutableString的话,其实指向的是同一个对象,如果修改可变字符串的话会影响不可变字符串的内容,所以要使用copy修饰
4.2 copy出来的字符串一定是不可变字符串,如果传入的是可变字符串,会发生深拷贝为不可变字符串,否则为浅拷贝。
4.3 mutablecopy,一定是深拷贝,拷贝出来的一定是可变字符串或者数组,即使传入的是不可变字符串或者数组。