zoukankan      html  css  js  c++  java
  • ios基础之 透过页面跳转来认识 Strong 与 Weak

       最近在自己做一个小程序,遇到了页面跳转的问题,然后上网一通乱搜,跳转的问题解决了,又有传值的问题。上面两个问题解决了,又发现内存比刚开始时多占用了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 @end
    11 
    12 @implementation BKViewController
    13 
    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)test
    23 {
    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)test
    25 {
    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;

    分析结束,如果不对之处希望指出共同学习。

     
  • 相关阅读:
    javascript如何封装函数
    addEventListener和attachEvent区别
    Infinity NaN undefined和null
    hasOwnProperty
    蜂巢式图片墙布局
    复选框使用总结
    文本框获得焦点时改变背景颜色
    自定义动画animate
    click()、bind()、live()和delegate()方法
    图片提示效果
  • 原文地址:https://www.cnblogs.com/chengzi/p/4545764.html
Copyright © 2011-2022 走看看