1.理解內(nèi)存中的區(qū)域
(1)棧區(qū):由系統(tǒng)自動(dòng)分配和釋放,存放局部變量的值,容量小,速度快,有序
(2)堆區(qū):自己分配和釋放,不釋放會(huì)出現(xiàn)內(nèi)存泄漏,容量大,速度慢,無需
(3)靜態(tài)儲(chǔ)存區(qū):全局變量和靜態(tài)變量?jī)?chǔ)存,程序結(jié)束,系統(tǒng)自動(dòng)回收
(4)常量區(qū):儲(chǔ)存常量,程序結(jié)束,系統(tǒng)自動(dòng)回收
(5)代碼區(qū):儲(chǔ)存代碼
2.copy關(guān)鍵字
(1)NSString,NSArray,NSDictionary 使用關(guān)鍵字
如果使用strong,可能會(huì)導(dǎo)致這個(gè)屬性指向一個(gè)可變對(duì)象,如果這個(gè)對(duì)象在外部被修改了,則這個(gè)對(duì)象也會(huì)受到影響,雖然copy和strong類似,但是copy的設(shè)置方法并不會(huì)保留新值,而是將其拷貝,來確保NSString等不會(huì)受到影響
如果在NSMutableArray等中使用copy,可能會(huì)導(dǎo)致崩潰,因?yàn)閏opy會(huì)復(fù)制出一份不可變的NSArray的對(duì)象,在進(jìn)行插入,刪除的時(shí)候會(huì)發(fā)生崩潰
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);
打印結(jié)果
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. 對(duì)非集合類對(duì)象的****copy****操作
- [immutableObject copy] // 淺復(fù)制
- [immutableObject mutableCopy] //深復(fù)制
- [mutableObject copy] //深復(fù)制
- [mutableObject mutableCopy] //深復(fù)制
所以可以看出,對(duì)immutable對(duì)象進(jìn)行copy,是指針復(fù)制,mutableCopy是內(nèi)容復(fù)制,深復(fù)制,對(duì)mutable對(duì)象copy和mutableCopy都是深復(fù)制
2.集合類對(duì)象的copy操作
集合類對(duì)象是指 NSArray、NSDictionary、NSSet ... 之類的對(duì)象
[immutableObject copy] // 淺復(fù)制
[immutableObject mutableCopy] //單層深復(fù)制
[mutableObject copy] //單層深復(fù)制
[mutableObject mutableCopy] //單層深復(fù)制
2 block中的copy
block中的copy是MVC留下來的傳統(tǒng),是為了將創(chuàng)建在棧區(qū)的block拷貝到堆區(qū),如果不拷貝的話,一旦在作用域之外來調(diào)用就會(huì)崩潰,另外,block在棧區(qū)里,但是很可能會(huì)用到一些變量,只要將其拷貝到堆區(qū),才可以使用這些變量。
但是在ARC里寫不寫都行,strong和copy都可以的
3.類用copy關(guān)鍵字,重寫copy關(guān)鍵字的setter方法
若想令自己所寫的對(duì)象具有拷貝功能,則需實(shí)現(xiàn) NSCopying 協(xié)議。如果自定義的對(duì)象分為可變版本與不可變版本,那么就要同時(shí)實(shí)現(xiàn) NSCopying 與 NSMutableCopying 協(xié)議。
- (id)copyWithZone:(NSZone *)zone;
淺復(fù)制和深復(fù)制
- (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關(guān)鍵字的setter方法
- (void)setName:(NSString *)name {
_name = [name copy];
}
3.@property中的屬性關(guān)鍵字解析和原理(ivar,getter,setter)等
(1)原子性和非原子性 atomicity,nonatomic
atomicity,是默認(rèn)的,原子的,使用了同步鎖,大量使用會(huì)影響性能,幾乎所有的屬性都是nonatomic,因?yàn)閍tomic并不能保證線程安全,例如如果一個(gè)線程在不斷讀取一個(gè)屬性值,但是另外一個(gè)線程在同時(shí)修改,就算有同步鎖,也還是會(huì)讀取到不同的屬性值的。而且考慮到性能問題,不應(yīng)該大量使用原子性。
(2)讀/寫 readwrite,readonly
使用讀寫屬性的時(shí)候一般是這個(gè)樣子的
.h文件
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
.m文件
@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
(3)assign,unsafe_unretained,strong,weak,copy
assign:assign是一個(gè)property的默認(rèn)屬性,可以用于非oc對(duì)象比如CGFloat 或 NSlnteger 等
@property (nonatomic) NSNumber *count;
等價(jià)于
@property (nonatomic, assign) NSNumber *count;
unsafe_unretained,聲明一個(gè)弱應(yīng)用,但是不會(huì)自動(dòng)nil化,也就是說,如果所指向的內(nèi)存區(qū)域被釋放了,這個(gè)指針就是一個(gè)野指針了。與assign幾乎等價(jià)
strong:標(biāo)識(shí)一中擁有關(guān)系
weak:標(biāo)識(shí)一種非擁有關(guān)系,weak 必須用于 OC 對(duì)象
(4) getter=<name>,setter=<name>
setter方法不常用,如果一個(gè)以init為開頭的屬性,重寫其setter方法的時(shí)候,系統(tǒng)會(huì)把init開頭的方法當(dāng)成初始化方法,所以要使用setter方法
(5)nonnull,null_resettable,nullable
__nullable指代對(duì)象可以為NULL或者為NIL
__nonnull指代對(duì)象不能為null
NS_ASSUME_NONNULL_BEGIN和NS_ASSUME_NONNULL_END 在這兩個(gè)宏之間的代碼,所有簡(jiǎn)單指針對(duì)象都被假定為nonnull
@property **的本質(zhì)是 **
```@property = ivar + getter + setter;
(“屬性” (property)有兩大概念:ivar(實(shí)例變量)、存取方法(access method = getter + setter)。
)```
property在runtime中是objc_property_t定義是一個(gè)結(jié)構(gòu)體
struct property_t {
const char *name;
const char *attributes;
};
而attributes本質(zhì)是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;
我們定義一個(gè)string的property@property (nonatomic, copy) NSString *string;,通過 property_getAttributes(property)獲取到attributes并打印出來之后的結(jié)果為T@"NSString",C,N,V_string
其中T就代表類型,可參閱Type Encodings,C就代表Copy,N代表nonatomic,V就代表對(duì)于的實(shí)例變量。
@interface Person : NSObject
@property NSString *firstName;
@end
等價(jià)于
@implementation Person
@synthesize firstName = _myFirstName;
@end
屬性實(shí)現(xiàn)
- OBJC_IVAR_$類名$屬性名稱 :該屬性的“偏移量” (offset),這個(gè)偏移量是“硬編碼” (hardcode),表示該變量距離存放對(duì)象的內(nèi)存區(qū)域的起始地址有多遠(yuǎn)。
- setter 與 getter 方法對(duì)應(yīng)的實(shí)現(xiàn)函數(shù)
- ivar_list :成員變量列表
- method_list :方法列表
- prop_list :屬性列表
當(dāng)我們?cè)黾右粋€(gè)屬性的時(shí)候,系統(tǒng)會(huì)在成員變量列表中增加一個(gè)實(shí)例變量,然后在方法列表里增加setter和getter方法,在屬性列表里增加屬性描述,在偏移量里增加偏移量
@synthesize****和****@dynamic
本質(zhì)上:都是 var = _var
@syntheszie 如果沒有實(shí)現(xiàn)setter和getter方法或者沒有實(shí)現(xiàn)其中一個(gè),編譯器會(huì)自動(dòng)給加上
@synthesize 合成實(shí)例變量的規(guī)則,有以下幾點(diǎn):
- 如果指定了成員變量的名稱,會(huì)生成一個(gè)指定的名稱的成員變量,
- 如果這個(gè)成員已經(jīng)存在了就不再生成了.
- 如果是 @synthesize foo; 還會(huì)生成一個(gè)名稱為foo的成員變量,也就是說:
如果沒有指定成員變量的名稱會(huì)自動(dòng)生成一個(gè)屬性同名的成員變量,
- 如果是 @synthesize foo = _foo; 就不會(huì)生成成員變量了.
@dynamic****則不會(huì),需要手動(dòng)加上****setter****和****getter****方法。
@protocol 和 category 中如何使用 @property
- 在 protocol 中使用 property 只會(huì)生成 setter 和 getter 方法聲明,我們使用屬性的目的,是希望遵守我協(xié)議的對(duì)象能實(shí)現(xiàn)該屬性
- category 使用 @property 也是只會(huì)生成 setter 和 getter 方法的聲明,如果我們真的需要給 category 增加屬性的實(shí)現(xiàn),需要借助于運(yùn)行時(shí)的兩個(gè)函數(shù):
- objc_setAssociatedObject
- objc_getAssociatedObject