我們在開發(fā)中聲明NSString,NSArray,NSDictionary ,block等一般都用copy來修飾,但是為什么要這么做,是不是非用copy不可,用strong行不行?很多iOS面試官也會問這個問題,那我就根據(jù)我自己的經(jīng)驗來說說這個問題,希望多多指正批評。
首先來了解一下OC的內(nèi)存管理。
說到Strong關(guān)鍵字那就要了解了解ARC(Automatic Reference Counting)之前和ARC之后的內(nèi)存管理。
OC內(nèi)存管理遵循“誰創(chuàng)建,誰釋放;誰引用,誰管理”的機制。當創(chuàng)建或引用一個對象的時候,需要向它發(fā)送alloc copy retain 消息,當釋放該對象時需要發(fā)送release消息,當該對象引用計數(shù)為0時,系統(tǒng)將釋放該對象,這是OC的手動內(nèi)存管理機制;
iOS5.0之后OC又提供了自動管理機制ARC,管理機制跟手動管理機制一樣,只是不再需要手動調(diào)用 retain release autorelease;它是 編譯時特性,當你啟用ARC時,在適當?shù)奈恢貌迦雛elease和autorelease;它引用了strong和weak 關(guān)鍵字,strong修飾的指針變量指向?qū)ο髸r,當指針指向新值,或者指針不再存在時,相關(guān)聯(lián)的對象就會自動釋放;而weak修飾的指針變量指向?qū)ο?,當對象的擁有者指向新值或者不存在時weak修飾的指針則自動置為nil,這是ARC管理機制
想深入了解內(nèi)存管理推薦一本《Objective-C高級編程》
言歸正傳
也就是說Strong和ARC之前的retain一樣都是使引用計數(shù)+1。
如果用strong修飾,不管屬性是可變類型還是不可變類型,指針都會指向通一塊內(nèi)存,例如
@interface BaseViewController ()
@property(nonatomic,strong)NSArray *array;
@property(nonatomic,strong)NSMutableArray *marray;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arraya = [[NSMutableArray alloc] initWithObjects:@"1", nil];
self.array = arraya;
self.marray = arraya;
[arraya addObject:@"2"];
NSLog(@"1-%p-%@",self.array,self.array);
NSLog(@"2-%p-%@",self.marray,self.marray);
NSLog(@"3-%p-%@",arraya,arraya);
}
@end
打印結(jié)果
1-0x600000054010-(
1,
2
)
2-0x600000054010-(
1,
2
)
3-0x600000054010-(
1,
2
)
先來了解下MutableCopy與Copy
對系統(tǒng)非容器類不可變對象調(diào)用Copy方法其實只是把當前對象的指針指向了原對象的地址,而調(diào)用mutableCopy方法則是新分配了一塊內(nèi)存區(qū)域并把新對象的指針指向了這塊區(qū)域。對于可變對象來說調(diào)用Copy和MutableCopy方法都會重新分配一塊內(nèi)存。但是copy和mutableCopy的區(qū)別在于copy在復(fù)制對象的時候其實是返回了一個不可變對象,因此當調(diào)用方法改變對象的時候會崩潰
容器對象和非容器對象在分別調(diào)用Copy和MutableCopy時沒有什么分別,不可變對象調(diào)用Copy方法只是增加了對原對象的指針的引用,調(diào)用MutableCopy方法是重新分配一塊內(nèi)存,然后把新對象指向新內(nèi)存。而對于可變對象不管調(diào)用Copy還是MutableCopy都是新分配一塊內(nèi)存。但是雖然重新分配了一塊內(nèi)存,但是對象里面的數(shù)據(jù)依然是指針復(fù)制的
情景一
#import "BaseViewController.h"
#import "TestModel.h"
@interface BaseViewController ()
@property(nonatomic,copy)NSArray *array;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *arraya = [[NSArray alloc] initWithObjects:@"1", nil];
self.array = arraya;
NSLog(@"1-%p-%@",self.array,self.array);
NSLog(@"3-%p-%@",arraya,arraya);
}
@end
輸出結(jié)果
1-0x60800000c970-(
1
)
3-0x60800000c970-(
1
)
由此可見這種情況下其實和strong效果一樣
情景二
#import "BaseViewController.h"
#import "TestModel.h"
@interface BaseViewController ()
@property(nonatomic,copy)NSArray *array;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arraya = [[NSMutableArray alloc] initWithObjects:@"1", nil];
self.array = arraya;
NSLog(@"1-%p-%@",self.array,self.array);
NSLog(@"3-%p-%@",arraya,arraya);
}
@end
輸出結(jié)果
1-0x600000200750-(
1
)
3-0x60000005f890-(
1,
2
)
由此可見NSMutableArray過copy之后重新分配了一塊內(nèi)存并由self.array指向改內(nèi)存,而且self.array依然是不可變的
情景三
#import "BaseViewController.h"
#import "TestModel.h"
@interface BaseViewController ()
@property(nonatomic,copy)NSMutableArray *array;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSMutableArray *arraya = [[NSMutableArray alloc] initWithObjects:@"1", nil];
self.array = arraya;
[arraya addObject:@"2"];
// [self.array addObject:@"3"];//程序崩潰
NSLog(@"1-%p-%@",self.array,self.array);
NSLog(@"3-%p-%@",arraya,arraya);
}
@end
輸出結(jié)果
1-0x60800001fd60-(
1
)
3-0x60800004fe10-(
1,
2
)
由此可見NSMutableArray過copy之變成了不可變數(shù)組,重新分配了一塊內(nèi)存并由self.array指向,self.array雖然聲明的是可變數(shù)組但其實已經(jīng)變成了不可變數(shù)組,所以調(diào)用addObject方法會崩潰
總結(jié):用copy還是用strong要根據(jù)自己的需求來決定