標籤:
最近在自己做一個小程式,遇到了頁面跳轉的問題,然後上網一通亂搜,跳轉的問題解決了,又有傳值的問題。上面兩個問題解決了,又發現記憶體比剛開始時多佔用了2M,於是,各種內心糾結,想徹底
搞清楚strong 和 weak 在ARC下到底是怎麼個意思,也順便理清了頁面跳轉之間的一些聯絡。
下面開始進入正題:(程式使用了storyboard)
由於頁面中使用了一個動態載入的tableview,所以沒法在頁面中拖segue來實現頁面跳轉,那麼只能在代碼中實現頁面跳轉了。
下面上一下頁面跳轉的小片段:
頁面A的控制器代碼 標頭檔
1 @interface BKViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>2 @property (weak, nonatomic) IBOutlet UITableView *tableview1;3 4 @property (strong, nonatomic) UIViewController *checkFT;5 @property (weak, nonatomic) UIViewController *checkFTWeak;6 @end
標頭檔中定義了3個屬性,
第一個屬性就是對應頁面上的一個tableview沒什麼好說的了。
第二個屬性:一個strong 的頁面B的控制器變數
第三個屬性:一個weak 的頁面B的控制器變數
具體幹什麼,稍後再說
1 @interface BKViewController () 2 { 3 BOOL _isRegistNib; 4 NSDateFormatter *_shortDateFormatter; 5 NSArray *tableData; 6 7 NSArray *kpType;//記賬類型 8 int pushCount;//紀錄跳轉次數 9 }10 @end11 12 @implementation BKViewController13 14 15 - (void)viewDidLoad {16 [super viewDidLoad];17 // Do any additional setup after loading the view.18 UIBarButtonItem *btnRight = [[UIBarButtonItem alloc] initWithTitle:@"測試" style:UIBarButtonItemStylePlain target:self action:@selector(test)];19 [self.navigationItem setRightBarButtonItem:btnRight];20 21 _isRegistNib = NO;22 _shortDateFormatter = [DateFormatterHelper getShortDateFormatter];23 //資金類型資料載入24 kpType = [NSArray arrayWithObjects:@"記賬日期",@"記賬類型",@"資金流動類型",@"費用科目",nil];25 [self loadTableViewData];26 self.tableview1.dataSource = self;27 self.tableview1.delegate = self;28 29 pushCount = 1;30 }
上面這段代碼主要關注pushCount這個變數,它記錄從A頁面跳往B頁面的次數,初始化為1
ok,準備工作完成了,下面說一下要實驗的步驟:
1)從頁面A 跳轉到 頁面B,跳轉之前,將weak的 checkFTWeak 指標指向 頁面B的對象;
2)然後回到頁面A
3)點擊測試按鈕,測試一下 checkFTWeak現在指向的對象是否還存在
4)我們要有一個籠統的概念:strong會持有對象(引用計數+1),weak不會
代碼:
1 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 /* 4 LycTableCellViewDefault *cell = (LycTableCellViewDefault *)[tableView cellForRowAtIndexPath:indexPath];*/ 5 6 NSLog(@"當前跳轉次數%i",pushCount); 7 //跳轉到選擇資金類型頁面 8 if (indexPath.section == 0 && indexPath.row == 1) { 9 UIStoryboard *sbMain = [UIStoryboard storyboardWithName:@"Main" bundle:nil];10 CheckFlowTypeViewController *cv = [sbMain instantiateViewControllerWithIdentifier:@"checkFlowTypeSB"];11 12 if (pushCount == 1) {13 self.checkFTWeak = cv;14 }15 NSLog(@"checkFTWeak指向的對象是%@", self.checkFTWeak);16 pushCount++;17 //[self presentViewController:cv animated:YES completion:nil ];18 [self.navigationController pushViewController: cv animated:YES];19 }20 }21 22 -(void)test23 {24 NSLog(@"checkFTWeak指向的對象是%@", self.checkFTWeak);25 }
首先初始化要跳轉到的頁面B對象 cv,然後將 checkFTWeak 指標指向 cv;接著就列印出對象的資訊
當從B 跳回 到A時,點擊A頁面的測試按鈕,再列印 checkFTWeak指標,看看它指向的對象還存在否
通過運行結果,我們看到,當頁面從B 返回 A 之後,checkFTWeak指向的對象,也就是那個頁面b不存在了。
那麼如果讓checkFT這個strong類型的屬性指向頁面b是什麼結果呢?
修改tableview選中事件的那句代碼為:self.checkFT = cv;
運行結果為:
可以看到,由於checkFT指標是strong類型的屬性,那麼他會持有頁面B的對象,導致記憶體不會釋放
結合上面兩個例子,可以總結下面兩點:
1)頁面跳轉時建立的目標頁面(就是頁面B),在返回後(也就是調用popViewController方法),將會被釋放
2)明白了strong和weak的區別,
strong指向的對象不會被釋放,除非把指標設定為nil;
而weak不會對指向的對象的引用計數有任何影響,在飲用對象不存在時,會返回nil,替我們做了處理;
那麼到這裡我還有一個疑問:如果strong類型的指標,本來指向 c,後來又指向d的話,那麼c會被釋放還是繼續存在?
那麼繼續來改造代碼,這個時候前面提到的pushCount參數就起作用了,具體實驗步驟如下:
1)從頁面A跳轉到頁面B,同時讓checkFT、 checkFTWeak 兩種類型的指標指向頁面B的對象
2)返回後列印兩個指標指向的對象
3)再次從頁面A跳轉到頁面B,但是strong類型的 checkFT指標指向新初始化的頁面B,checkFTWeak指標還是指向原來的那個對象
4)返回頁面A,列印兩個指標指向的對象
修改後的代碼:
1 -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 2 { 3 /* 4 LycTableCellViewDefault *cell = (LycTableCellViewDefault *)[tableView cellForRowAtIndexPath:indexPath];*/ 5 6 NSLog(@"當前跳轉次數%i",pushCount); 7 //跳轉到選擇資金類型頁面 8 if (indexPath.section == 0 && indexPath.row == 1) { 9 UIStoryboard *sbMain = [UIStoryboard storyboardWithName:@"Main" bundle:nil];10 CheckFlowTypeViewController *cv = [sbMain instantiateViewControllerWithIdentifier:@"checkFlowTypeSB"];11 self.checkFT = cv;12 13 if (pushCount == 1) {14 self.checkFTWeak = cv;15 }16 NSLog(@"checkFT指向的對象是%@",self.checkFT);17 NSLog(@"checkFTWeak指向的對象是%@", self.checkFTWeak);18 pushCount++;19 //[self presentViewController:cv animated:YES completion:nil ];20 [self.navigationController pushViewController: cv animated:YES];21 }22 }23 24 -(void)test25 {26 NSLog(@"點擊測試按鈕後:");27 NSLog(@"checkFT指向的對象是%@",self.checkFT);28 NSLog(@"checkFTWeak指向的對象是%@", self.checkFTWeak);29 }
啟動並執行結果:
第一次跳轉因為有strong類型的指標checkFT給weak類型的指標checkFTWeak撐腰,所以他倆指向對象一樣。
在返回頁面A後,發生第二次跳轉錢checkFT指向了新的頁面B的對象,checkFTWeak指向的對象被釋放了,所以列印出了nil
那麼又得出了第三個結論:
當strong類型的指標從指向a變成指向b之後,原來的a對象的引用計數將會-1,如果沒有其他指標持有它,它變被arc給釋放了。然後b的引用計數會+1;
分析結束,如果不對之處希望指出共同學習。
ios基礎之 透過頁面跳轉來認識 Strong 與 Weak