注意:這裡沒有添加autorelease@implementation Person+ (instancetype)person { // autorelease 作用就是延遲釋放 // 給對象添加延遲釋放的標記 Person *p = [[Person alloc] init] ; return p;}- (void)dealloc { NSLog(@"我去了"); [super dealloc];}@end
聲明Persion變數:
@property (nonatomic, assign) Person *p;
測試Demo:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. self.p = [Person person]; NSLog(@"%@", self.p);}
運行結果:
2015-03-25 10:44:16.652 10-ARC自動釋放[27546:726446]
小結:在MRC下,如果提供的類方法沒有autorelease,那麼在調用的時候,用assign變數接收,仍然會列印出對象的地址,當然對象並沒有銷毀(dealloc沒有輸出
)。
將類方法帶上 autoreleasePerson *p = [[[Person alloc] init] autorelease];
列印結果:
2015-03-25 10:56:04.224 10-ARC自動釋放[27690:732059] 2015-03-25 10:56:04.238 10-ARC自動釋放[27690:732059] 我去了
可以看到對象被釋放了,說明autorelease給對象添加了延遲釋放
的標記,讓對象在自動是釋放池銷毀,或者出了離它最近的自動釋放池範圍的時候,自動釋放。
ARC中的自動釋放變數的聲明:
@property (nonatomic, weak) Person *p;@property (nonatomic, weak) UIButton *button;
測試Demo:
// ARC 中,如果給 weak 做 alloc / init 的設定數值,Xcode 會提示! self.p = [[Person alloc] init]; // 對於 Xcode 編譯器而言,只要是類方法,就不會提示! // 如果使用 MRC 開發,所有 返回 instancetype 的類方法,返回的對象都是 autorelease 的! // 因為沒有強引用,會被立即釋放 self.p = [Person person]; // ARC中之所以為 null,是因為 weak,跟autorelease沒有關係! NSLog(@"%@", self.p); // 之所以會這樣是因為蘋果架構的底層是用 MRC 寫的,buttonWithType返回的對象是帶有 autorelease self.button = [UIButton buttonWithType:UIButtonTypeContactAdd]; NSLog(@"%@", self.button);
列印結果:
2015-03-25 11:00:58.756 10-ARC自動釋放[27778:735123] (null)2015-03-25 11:00:58.769 10-ARC自動釋放[27778:735123] >
小結
- 如果普通對象的alloc,且對象是weak的,Xcode會自動提示警告,告訴你這個對象,一建立就會被銷毀啦
- 但是如果你提供了一個類方法,快速產生。即使內部寫的是alloc,Xcode也不會警告你,但是你不能改變一建立就被銷毀的事實。
- 蘋果自己提供的類方法建立的button,我們用weak接收,卻沒有銷毀,為啥呢,因為蘋果架構的底層是用MRC寫的,buttoWithType:返回的對象都是帶
autorelease
的,意味著會延遲銷毀,僅僅是被添加到自動釋放池而已,等待著出自動釋放池範圍或者自動釋放池銷毀。而不會立刻銷毀。一道經典面試題問題:以下代碼是否有問題?如果有,如何解決?
for (long i = 0; i < largeNumber; ++i) { @autoreleasepool { NSString *str = [NSString stringWithFormat:@"hello - %ld", i]; str = [str uppercaseString]; str = [str stringByAppendingString:@" - world"]; } }
答案:如果 largeNumber 非常大,會建立太多自動釋放的對象,有可能會把自動釋放池"撐滿" 提示:經常一次使用者互動,遠遠不止一個 for,在 for 的前後,會有很多的代碼,但是這個 for 會佔用大量的自動釋放池空間
解決方案引入自動釋放池,網路上有兩種解決方案!
1> 外面加自動釋放池(快):能夠保證for迴圈結束後,內部產生的自動釋放對象,都會被銷毀 需要等到 for 結束後,才會釋放記憶體 2> 裡面加自動釋放池(慢):能夠每一次 for 都釋放產生的自動釋放對象! 提問:那種方式效率高!速度差不多!大多數測試內部比外部外! 如果面試中問道:要說裡面的略快,“親測”!!! 提示:在日常工作中!有的時候,真的會出現代碼記憶體飆升的情況!要知道解決辦法!
設定largeNumner的數值:
long largeNumber = 5 * 1000 * 1000;
測試Demo:
NSLog(@"內部 start"); CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); for (long i = 0; i < largeNumber; ++i) { @autoreleasepool { NSString *str = [NSString stringWithFormat:@"hello - %ld", i]; str = [str uppercaseString]; str = [str stringByAppendingString:@" - world"]; } } NSLog(@"end - %f", CFAbsoluteTimeGetCurrent() - start); [self answer1];
answer1方法:
NSLog(@"外面 start"); CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); @autoreleasepool { for (long i = 0; i < largeNumber; ++i) { NSString *str = [NSString stringWithFormat:@"hello - %ld", i]; str = [str uppercaseString]; str = [str stringByAppendingString:@" - world"]; } } NSLog(@"end - %f", CFAbsoluteTimeGetCurrent() - start);
測試結果:
2015-03-25 11:18:50.663 12-自動釋放池的面試題[28015:743360] 內部 start2015-03-25 11:19:03.996 12-自動釋放池的面試題[28015:743360] end - 13.3323712015-03-25 11:19:03.996 12-自動釋放池的面試題[28015:743360] 外面 start2015-03-25 11:19:18.227 12-自動釋放池的面試題[28015:743360] end - 14.230752
由測試結果可以知道,對於500w次迴圈,內部、外部添加autorelease,速度其實差不多,內部略微快一點,但這是取決於編譯器。 但是,在外部添加autorelease會佔用極大的記憶體(注意,這裡跟不加autorelease不一樣,不加autorelease開闢的記憶體是不會釋放的)。 開發中,通常在內部添加。