1.理解内存中的区域
(1)栈区:由系统自动分配和释放,存放局部变量的值,容量小,速度快,有序
(2)堆区:自己分配和释放,不释放会出现内存泄漏,容量大,速度慢,无需
(3)静态储存区:全局变量和静态变量储存,程序结束,系统自动回收
(4)常量区:储存常量,程序结束,系统自动回收
(5)代码区:储存代码
2.copy关键字
(1)NSString,NSArray,NSDictionary 使用关键字
如果使用strong,可能会导致这个属性指向一个可变对象,如果这个对象在外部被修改了,则这个对象也会受到影响,虽然copy和strong类似,但是copy的设置方法并不会保留新值,而是将其拷贝,来确保NSString等不会受到影响
如果在NSMutableArray等中使用copy,可能会导致崩溃,因为copy会复制出一份不可变的NSArray的对象,在进行插入,删除的时候会发生崩溃
NSArray *array = @[ @1, @2, @3, @4 ];
NSMutableArray *mutableArray = [NSMutableArray arrayWithArray:array];
self.array = mutableArray;
[mutableArray removeAllObjects];;
NSLog(@"%@",self.array);
[mutableArray addObjectsFromArray:array];
self.array = [mutableArray copy];
[mutableArray removeAllObjects];;
NSLog(@"%@",self.array);
打印结果
2015-09-27 19:10:32.523 CYLArrayCopyDmo[10681:713670] (
)
2015-09-27 19:10:32.524 CYLArrayCopyDmo[10681:713670] (
1,
2,
3,
4
)
1. 对非集合类对象的****copy****操作
- [immutableObject copy] // 浅复制
- [immutableObject mutableCopy] //深复制
- [mutableObject copy] //深复制
- [mutableObject mutableCopy] //深复制
所以可以看出,对immutable对象进行copy,是指针复制,mutableCopy是内容复制,深复制,对mutable对象copy和mutableCopy都是深复制
2.集合类对象的copy操作
集合类对象是指 NSArray、NSDictionary、NSSet ... 之类的对象
[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //单层深复制
[mutableObject copy] //单层深复制
[mutableObject mutableCopy] //单层深复制
2 block中的copy
block中的copy是MVC留下来的传统,是为了将创建在栈区的block拷贝到堆区,如果不拷贝的话,一旦在作用域之外来调用就会崩溃,另外,block在栈区里,但是很可能会用到一些变量,只要将其拷贝到堆区,才可以使用这些变量。
但是在ARC里写不写都行,strong和copy都可以的
3.类用copy关键字,重写copy关键字的setter方法
若想令自己所写的对象具有拷贝功能,则需实现 NSCopying 协议。如果自定义的对象分为可变版本与不可变版本,那么就要同时实现 NSCopying 与 NSMutableCopying 协议。
- (id)copyWithZone:(NSZone *)zone;
浅复制和深复制
- (id)copyWithZone:(NSZone *)zone {
CYLUser *copy = [[[self class] allocWithZone:zone]
initWithName:_name
age:_age
sex:_sex];
copy->_friends = [_friends mutableCopy];
return copy;
}
- (id)deepCopy {
CYLUser *copy = [[[self class] alloc]
initWithName:_name
age:_age
sex:_sex];
copy->_friends = [[NSMutableSet alloc] initWithSet:_friends
copyItems:YES];
return copy;
}
重写copy关键字的setter方法
- (void)setName:(NSString *)name {
_name = [name copy];
}
3.@property中的属性关键字解析和原理(ivar,getter,setter)等
(1)原子性和非原子性 atomicity,nonatomic
atomicity,是默认的,原子的,使用了同步锁,大量使用会影响性能,几乎所有的属性都是nonatomic,因为atomic并不能保证线程安全,例如如果一个线程在不断读取一个属性值,但是另外一个线程在同时修改,就算有同步锁,也还是会读取到不同的属性值的。而且考虑到性能问题,不应该大量使用原子性。
(2)读/写 readwrite,readonly
使用读写属性的时候一般是这个样子的
.h文件
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
.m文件
@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
(3)assign,unsafe_unretained,strong,weak,copy
assign:assign是一个property的默认属性,可以用于非oc对象比如CGFloat 或 NSlnteger 等
@property (nonatomic) NSNumber *count;
等价于
@property (nonatomic, assign) NSNumber *count;
unsafe_unretained,声明一个弱应用,但是不会自动nil化,也就是说,如果所指向的内存区域被释放了,这个指针就是一个野指针了。与assign几乎等价
strong:标识一中拥有关系
weak:标识一种非拥有关系,weak 必须用于 OC 对象
(4) getter=
setter方法不常用,如果一个以init为开头的属性,重写其setter方法的时候,系统会把init开头的方法当成初始化方法,所以要使用setter方法
(5)nonnull,null_resettable,nullable
__nullable指代对象可以为NULL或者为NIL
__nonnull指代对象不能为null
NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END 在这两个宏之间的代码,所有简单指针对象都被假定为nonnull
@property **的本质是 **
```@property = ivar + getter + setter;
(“属性” (property)有两大概念:ivar(实例变量)、存取方法(access method = getter + setter)。
)```
property在runtime中是objc_property_t定义是一个结构体
struct property_t {
const char *name;
const char *attributes;
};
而attributes本质是objc_property_attribute_t,定义了property的一些属性,定义如下:
/// Defines a property attribute
typedef struct {
const char *name; /**< The name of the attribute */
const char *value; /**< The value of the attribute (usually empty) */
} objc_property_attribute_t;
我们定义一个string的property@property (nonatomic, copy) NSString *string;,通过 property_getAttributes(property)获取到attributes并打印出来之后的结果为T@"NSString",C,N,V_string
其中T就代表类型,可参阅Type Encodings,C就代表Copy,N代表nonatomic,V就代表对于的实例变量。
@interface Person : NSObject
@property NSString *firstName;
@end
等价于
@implementation Person
@synthesize firstName = _myFirstName;
@end
属性实现
- OBJC_IVAR_$类名$属性名称 :该属性的“偏移量” (offset),这个偏移量是“硬编码” (hardcode),表示该变量距离存放对象的内存区域的起始地址有多远。
- setter 与 getter 方法对应的实现函数
- ivar_list :成员变量列表
- method_list :方法列表
- prop_list :属性列表
当我们增加一个属性的时候,系统会在成员变量列表中增加一个实例变量,然后在方法列表里增加setter和getter方法,在属性列表里增加属性描述,在偏移量里增加偏移量
@synthesize****和****@dynamic
本质上:都是 var = _var
@syntheszie 如果没有实现setter和getter方法或者没有实现其中一个,编译器会自动给加上
@synthesize 合成实例变量的规则,有以下几点:
- 如果指定了成员变量的名称,会生成一个指定的名称的成员变量,
- 如果这个成员已经存在了就不再生成了.
- 如果是 @synthesize foo; 还会生成一个名称为foo的成员变量,也就是说:
如果没有指定成员变量的名称会自动生成一个属性同名的成员变量,
- 如果是 @synthesize foo = _foo; 就不会生成成员变量了.
@dynamic****则不会,需要手动加上****setter****和****getter****方法。
@protocol 和 category 中如何使用 @property
- 在 protocol 中使用 property 只会生成 setter 和 getter 方法声明,我们使用属性的目的,是希望遵守我协议的对象能实现该属性
- category 使用 @property 也是只会生成 setter 和 getter 方法的声明,如果我们真的需要给 category 增加属性的实现,需要借助于运行时的两个函数:
- objc_setAssociatedObject
- objc_getAssociatedObject