一,property有哪些属性?默认属性是什么?
http://www.jianshu.com/p/8e5a70301844
1,assign,weak:
assign:setter方法直接赋值,不做retain操作;并且属性被释放之后,不会被置为nil,因此如果用户NSObject对象,是不安全的
weak:弱引用,对象虽然被引用,但引用计数不会增加;对象被释放之后,会被置为nil,不会产生野指针;用于NSObject对象的弱引用中,特别是代理
2,copy,strong,retain:
retain,strong:
始终是浅复制。引用计数每次加一。返回对象是否可变与被复制的对象保持一致。
copy:
1,对于可变对象为深复制,引用计数不改变;对于不可变对象是浅复制, 引用计数每次加一。
2,注意:不论使用copy还是strong对NSMutableArray进行修饰
@property (nonatomic, copy) NSMutableArray *mutArr1;
@property (nonatomic, strong) NSMutableArray *mutArr2;
如果是非可变的数组赋值给他们,他们也只是进行了浅拷贝;
此时,self.mutArr1实际指向的是一个不可变数组,即不可变的内存空间,我们如果进行可变数组的
addObject:
方法,程序将奔溃// 非可变数组arr赋值给arr self.mutArr1 = arr; // 出现警告 // 调用可变数组的方法 [self.mutArr1 addObject:@"222"];
而可变的数组赋值时,copy为深拷贝,strong为浅拷贝,依然遵循第一条原则。
分析:
1,非容器类:
@property (nonatomic, copy) NSString *copStr; @property (nonatomic, strong) NSString *strongStr; @property (nonatomic, retain) NSString *retainStr;
a,非可变(包括NSNumber)
NSString *str0 = @"1111"; self.copStr = str0; self.strongStr = str0; self.retainStr = str0;
copy,strong,retain都是浅拷贝;
此时改变str0,改变的只是str0的指针,将指针指向一块新的内存地址,copStr,strongStr和retainStr不会受到影响b,可变(NSMutableString)
NSMutableString *str4 = [NSMutableString stringWithFormat:@"222"]; self.copStr = str4; self.strongStr = str4; self.retainStr = str4;
copy是一个深拷贝,指向了一个新开辟的内存空间;
strong和retain是浅拷贝;2,容器类
NSArray,NSMutableArray,NSSet,NSMutableSet
不可变NSArray *arr = @[[Person new], [Person new], [Person new]]; NSLog(@"arr = %p", arr); NSLog(@"arr = %@", arr); self.copArr = arr; NSLog(@"copArr = %p", self.copArr); NSLog(@"copArr = %@", self.copArr); self.strongArr = arr; NSLog(@"strongArr = %p", self.strongArr); NSLog(@"strongArr = %@", self.strongArr); self.retainArr = arr; NSLog(@"retainArr = %p", self.retainArr); NSLog(@"retainArr = %@", self.retainArr);
copy,retain,strong:对数组进行浅拷贝
可变
NSMutableArray *mutArr = arr.mutableCopy; NSLog(@"mutArr = %p", mutArr); NSLog(@"mutArr = %@", mutArr); self.copArr = mutArr; NSLog(@"copArr = %p", self.copArr); NSLog(@"copArr = %@", self.copArr); self.strongArr = mutArr; NSLog(@"strongArr = %p", self.strongArr); NSLog(@"strongArr = %@", self.strongArr); self.retainArr = mutArr; NSLog(@"retainArr = %p", self.retainArr); NSLog(@"retainArr = %@", self.retainArr);
copy:对数组进行了深拷贝,对数组中存储的元素进行的是浅拷贝
retain和strong:对数组进行浅拷贝
3,atomic和nonatomic
atomic:原子性,属性的getter方法和setter方法中会使用同步锁,保护多线程下对属性的读写安全;atomic也仅仅只能保证getter方法和setter方法内部是线程安全的,实际的开发中,线程安全问题还是需要程序员使用锁进行管理;并且在iOS系统中,锁操作耗费性能,因此开发中我们都将属性定义为nonatomic
nonatomic:非原子性,与atomic相反
注意:
1,如果属性没有声明为nonatomic,则默认为atomic
2,如果重写了setter方法和getter方法,那么就应该遵从与属性特质相符的原子性
4,readwrite(读写)、readonly (只读)
这两个属性的意义在于限制对象的访问级别;
readwrite:属性会生成getter方法和setter方法,可读可写;
readonly:属性值生成getter方法,不生成setter方法,可读不可写;如果在.m文件中需要进行写操作,可在.m文件中重新声明为readwrite,这样对于外部属性是只读的,对内是可读可写的;
需要注意的是,属性默认是readwrite的
5,unsafe_unretained
unsafe_unretained作用等同于weak;但对象释放的时候,指针不会置为nil,产生野指针
6,getter = <name> 、setter = <name>
重新定义属性的getter方法和setter方法的方法名;如果设置了,默认的getter方法和setter方法将无效,取而代之的是自定义的getter方法和setter方法;
在OC中属性命名不能使用new
,init
开头(变量是可以的)
@property (nonatomic, strong) NSString *newName;
但可以通过修改getter方法来解决
@property (nonatomic, strong, getter=lg_newName) NSString *newName;
原因是:
以new
或init
开头的属性,默认生成的getter方法为new属性
或init属性吗
,这是不被OC允许的;我们只要修改getter方法不以这两个关键字开头即可
7,nullable,nonnull,null_resettable,null_unspecified
http://www.jianshu.com/p/1f672a441052
nullable:属性setter方法传入参数可以为空 nonnull:属性setter方法传入参数不能为空 null_resettable:属性getter方法返回参数不能为空 null_unspecified:属性getter方法返回参数未知(可以为空)
property默认属性:
readwrite,strong,atomic,nullable,null_unspecified
1,默认属性的对象是可读可写的,因此是readwriter;
2,测试默认为strong,weak还是assagn?
思路:
1,不是weak
自定义Person类,实现dealloc方法,打印销毁信息
@implementation Person - (void)dealloc { NSLog(@"Person对象释放"); } @end
如果Person的实例使用不同的property结果如下:
weak:赋值之后,到下一行代码,对象被销毁(指针置为nil),dealloc被调用
assagn:对象没有被销毁,不调用dealloc方法;之后如果使用Person实例,会导致程序奔溃
strong:对象不会被销毁,不调用dealloc方法默认属性时,dealloc方法没有被调用
@property Person *def;
2,不是assign
self.person = [Person new]; NSLog(@"self.person = %@", self.person);
使用assagn修饰时,self.person被赋值之后,到下一行代码时,对象不是否了,当时指针没有被置为nil,因此导致程序奔溃。如果使用strong修饰,程序正常通过。
默认属性时,上面的代码没有导致奔溃,说明不是assagn
问题:assign和weak的区别?
区别:
assign适用于基本数据类型,weak适用于NSObject对象,并且是一个弱引用。
assign其实也可以用来修饰对象,那么我们为什么不用它呢?
因为被assign修饰的对象在释放之后,指针的地址还是存在的,也就是说指针并没有被置为nil,成为野指针。如果在后面的操作中又用到了这个野指针,则会导致程序崩溃。
而weak修饰的对象在释放之后,指针地址会被置为nil。对空对象发送消息,程序是不会崩溃的。
所以现在一般弱引用就是用weak。
验证:
方法一:自定义对象,实现dealloc方法,观察dealloc方法是否被调用
@implementation Person - (void)dealloc { NSLog(@"Person对象释放"); } @end
方法二:观察对象的值
注意:
NSString对象比较特殊。
对于NSString对象,assign和weak的结果是一样的@property (nonatomic, assign) NSString *str1; @property (nonatomic, weak) NSString *str2; self.str1 = @"111"; self.str2 = @"222"; NSLog(@"%@ == %@", self.str1, self.str2); 输出结果: 111 == 222
非NSString对象
@property (nonatomic, assign) NSObject *obj1; @property (nonatomic, weak) NSObject *obj2; self.obj1 = [NSObject new]; self.obj2 = [NSObject new]; NSLog(@"%@ == %@", self.obj1, self.obj2);
结果:
程序运行会导致奔溃。断点查看self.obj1
和self.obj2
对象的值,self.obj2
被置为nil了。
问题:retain和strong的区别?
1,在MRC下用于修饰Block时的区别:
在Block中截获自动变量时(没有截获自动变量,Block都在数据区域中,没有区别)
@property (nonatomic, copy) void(^copyBlock)(void);
@property (nonatomic, retain) void(^retainBlock)(void);
@property (nonatomic, assign) void(^assignBlock)(void);
@property (nonatomic, strong) void(^strongBlock)(void);
NSLog(@"======================================================");
self.copyBlock = ^{
NSLog(@"a = %d", a);
NSLog(@"======================================================");
};
NSLog(@"copyBlock info:%@", self.copyBlock);
self.copyBlock();
self.retainBlock = ^{
NSLog(@"a = %d", a);
NSLog(@"======================================================");
};
NSLog(@"retainBlock info:%@", self.retainBlock);
self.retainBlock();
self.assignBlock = ^{
NSLog(@"a = %d", a);
NSLog(@"======================================================");
};
NSLog(@"assignBlock info:%@", self.assignBlock);
self.assignBlock();
self.strongBlock = ^{
NSLog(@"a = %d", a);
NSLog(@"======================================================");
};
NSLog(@"strongBlock info:%@", self.strongBlock);
self.strongBlock();
void(^block)(void) = ^{
NSLog(@"a = %d", a);
NSLog(@"======================================================");
};
NSLog(@"局部blockinfo:%@", block);
block();
输出结果:
2018-01-05 11:14:04.932328+0800 MRCDemo[1643:1334438] ======================================================
2018-01-05 11:14:04.932648+0800 MRCDemo[1643:1334438] copyBlock info:<__NSMallocBlock__: 0x1c805b9c0>
2018-01-05 11:14:04.932710+0800 MRCDemo[1643:1334438] a = 10
2018-01-05 11:14:04.932780+0800 MRCDemo[1643:1334438] ======================================================
2018-01-05 11:14:04.932985+0800 MRCDemo[1643:1334438] retainBlock info:<__NSStackBlock__: 0x16f78be40>
2018-01-05 11:14:04.933058+0800 MRCDemo[1643:1334438] a = 10
2018-01-05 11:14:04.933113+0800 MRCDemo[1643:1334438] ======================================================
2018-01-05 11:14:04.933196+0800 MRCDemo[1643:1334438] assignBlock info:<__NSStackBlock__: 0x16f78be18>
2018-01-05 11:14:04.933243+0800 MRCDemo[1643:1334438] a = 10
2018-01-05 11:14:04.933290+0800 MRCDemo[1643:1334438] ======================================================
2018-01-05 11:14:04.933372+0800 MRCDemo[1643:1334438] strongBlock info:<__NSMallocBlock__: 0x1c4243450>
2018-01-05 11:14:04.933417+0800 MRCDemo[1643:1334438] a = 10
2018-01-05 11:14:04.933463+0800 MRCDemo[1643:1334438] ======================================================
2018-01-05 11:14:04.933625+0800 MRCDemo[1643:1334438] 局部blockinfo:<__NSStackBlock__: 0x16f78bdc0>
2018-01-05 11:14:04.933704+0800 MRCDemo[1643:1334438] a = 10
2018-01-05 11:14:04.934095+0800 MRCDemo[1643:1334438] ======================================================
上面的结果中可以看出,在截获自动变量的情况下,使用assign
和retain
修饰的Block在栈区,没有进行copy操作;使用copy
和strong
修饰,Block分配分配在堆区,进行了copy操作
局部的block在截获自动变量的情况下,开辟在栈区
问题:OC对象使用什么属性修饰?
NSString:使用copy