从简单的顺传窥视底层的诸多细节

简述



通常在开发中,大多数人关注的往往都是技术,只是希望学习更多新的技术。但是,我认为每一个新的技术内部用到的都是很多基本内容。
因此,本文着重通过一个基本的 顺传 来了解其中遇到的问题和相应的分析方法。

看过本文之后,能够学习到的内容:


  • 顺传的原则
  • 对于控制器view 的懒加载的理解
  • 如何进行调试
  • viewDidLoad 和viewWillAppear的使用及调用顺序
  • 实现顺传的三种方式

效果图如下



其中,window的根控制器是rootViewController是导航控制器。


the show of the view.gif


如上图所示,实现起来很简答。当点击按钮“点击跳转”时,就会跳转到另一个View上。同时,将显示在该View上的label上的内容传递到第二个控制器的页面的label上。


实现的条件



本文为了方便解释,在跳转时展示,使用的是storyboard进行搭建的页面。



顺传的原则



基本上,如果通过顺传,则需要遵循如下两个原则即可。
1. 目标控制器得有属性进行接收
2. 要拿到目标控制器
这两个原则就是就是将数据从一个view传递到另一个view时需要遵循的。

通过在storyboard中,进行脱线从而实现跳转的功能。因此当调用performSegueWithIdentifier 方法时候,内部会自动调用方法:prepareForSegue相应的方法。因此可以在该方法内部做跳转前的一些配置信息。

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    
    NSLog(@"%@",segue.destinationViewController);
    
    ToViewController *toVC = segue.destinationViewController;
    
    //由于控制器的 View 是懒加载的.因此只有加载了,才可以分配内存空间.
    //方法一:提前加载 view.
     toVC.view.backgroundColor = [UIColor redColor];

     toVC.toLabel.text = self.fromLabel.text;
}

对于控制器view 的懒加载的理解

为了方便解释控制器的跳转的逻辑,在此处用如下的方式进行表述:`A控制器跳转到B控制器`

正如上部分代码展示的一样,其中展示的是方法一:

由于控制器的view是懒加载的。故首先将B控制器的view提前加载后,这时候才能加载B控制器,然后分配相应的内存空间。这时候B内的属性才能有地方存放接收到的数据,而不会被释放。

通过添加断点,然后进行打印,结果如下图所示:

the debug result.png
分析调试结果:

当执行如下的语句时

toVC.view.backgroundColor = [UIColor redColor];
toVC.toLabel.text = self.fromLabel.text;

首先,由于当执行第一条语句的时候,会加载toVC的view,因此内部具体的操作是:

  • 先调用toVC的viewDidLoad方法,然后分配相应的内存空间;
  • 接着给toVC的属性也分配相应的内存空间
  • 由于toVC.toLabel该UI控件直接从storyboard进行脱线。
  • 故该控件不仅分配响应的内存控件,并且进行相应的初始化操作(就是将一个UILabel拖到storyboard中的时候,label的默认text值为@“label”)。
  • 从上图中 the debug result 可以看到
    • 当执行完第一行代码后,显示的结果为

      (lldb) p toVC.toLabel.text
      (NSTaggedPointerString *) $0 = 0xa00006c6562614c5   @"Label"
      
      • 因此,可以看出来,此时toVC.toLabel的值是原来storyboard中的初始化的值Label
    • 当执行完第二条语句,从该图the debug result可以看到

      (lldb) p toVC.toLabel.text
      (__NSCFConstantString *) $1 = 0x000000010e5840a0 @"顺传,,出去"
      
      • 其内部具体做的操作就是:在堆内存中将toVC.toLabel.text指向self.fromLabel.text.我们知道,text是字符串,而在OC中字符串是一个对象,因此他们转为C语言的变化是:
        将NSString -> NSCFString
        而在C语言中,字符串 是一个指针,具体是指向一个字符的指针
        因此传递的是地址。而当类型char *c = "fdsfsd"时候,也就是在一个缓冲队列中的保存一堆字符。

如何进行调试



the debug result图片中,可以看到。使用的命令有p ,相应的还有其他的命令po。他们两者的主要区别是,p同时能够打印两该变量在内存中的存储位置信息。这两种在调试过程中最常用。

   使用前提:
       1. 程序中有断点;
       2. 只能查看当前{}内的相应的变量的信息。
         当查看{}外部的信息的时候,可能出现呢error。
       3. 当查看具体{}内响应对象等信息的时候,一定要加上完整的前缀。

针对上述的内容the debug result,例如查看toLabel的信息,不能直接输入p toLabel,这样会报错的。因为找不到。而应该输入:p toVC.toLabel就可以查看相应的信息。


viewDidLoad 和viewWillAppear的使用及调用顺序


  • 调用顺序
    这个目前毋庸置疑的是,他们两个的调用的顺序为:viewDidLoad -> viewWillAppear .
  • 通常情况下,进行相应的初始化操作信息,是通过在view加载完成(viewDidLoad),view显示之前(viewWillAppear)进行的初始化操作。而viewWillAppear的使用,有时候是为了覆盖之前在viewDidLoad中的某些操作,或者通过重新赋值来改变相应值操作。在代码中的在下一板块中体现。

实现顺传的三种方式


    1. 方式一:通过B控制器的view提前进行加载的方式进行处理(上述已经展示过)
    2. 方式二:通过将要传递的内容封装成模型,然后传递过去
    3. 方式三:通过额外增加一个UILabel,使其作为B控制器属性,手动为其分配存储空间。

注意点:以上三种方式都是通过给新的对象分配相应的内存空间的方式进行处理的。只不过有些是通过隐式的方式,进行分配而已。其本质都是一样的。在swift中,会对其有更好的理解。

  • 方式一上述已经讨论过

  • 方式二:代码如下

    1. 模型代码
          @interface Content : NSObject
          //声明模型属性
          @property (nonatomic, copy) NSString *name;
    
          @end
    
    1. 控制器的代码
    - (void)prepareForSegue:(UIStoryboardSegue *)segue sender: (id)sender {
      NSLog(@"%@",segue.destinationViewController);
    
      ToViewController *toVC = segue.destinationViewController;
              //方法三:通国模型进行传递
             toVC.cont.name = self.fromLabel.text;
            }
    
    1. 懒加载模型的代码(实质是分配内存空间进行保存
    - (Content *)cont {
     if (!_cont) {
         _cont = [[Content alloc]init];
     }
     return _cont;
    }
    

通过对此三小份额代码的分析。其思想是:定义模型进行保存将要传递的name。然后拿到B控制器的模型属性进行赋值,由于赋值的时候,为了让con能够保存传递的信息,因此要给其分配内存空间进行保存将要传递的数据。故可以通过懒加载的方式,给其分配相应的存储空间。

  • 方式三:代码如下

    1. 懒加载额外的label(otherLabel)代码
      - (UILabel *)OtherLabel {
          if (!_OtherLabel) {
          
          UILabel *otherLabel = [[UILabel alloc]init];
          /*
           若不想要该控件进行显示,因此可以不设置尺寸,从而不会显示出来.
           UILabel *otherLabel = [[UILabel alloc]initWithFrame:CGRectMake(50, 50, 100, 50)];
          */
          otherLabel.backgroundColor = [UIColor redColor];
          
          self.OtherLabel = otherLabel;
          
           // 只有将 weak 的属性加载到 self.view 上之后,才会进行强引用,而不会导致释放.
          [self.view addSubview:_OtherLabel];
          }
        /**
         若没有强指针指向 _OtherLabel,当从上一个`}`出来之后,就会自动释放.
         NSLog(@"--%@", _OtherLabel);// nil
         */
        return _OtherLabel;
      }
    
    1. 重新赋值toLabel的内容
    - (void)viewWillAppear:(BOOL)animated{
    
        self.toLabel.backgroundColor = [UIColor greenColor];
        self.toLabel.text = self.OtherLabel.text;
    }
    
    1. 定义新的属性label
          #import <UIKit/UIKit.h>
          @class Content;
    
          @interface ToViewController : UIViewController
          //不能以关键字作为命名的开头
          @property (weak, nonatomic) UILabel *OtherLabel;
    
          @end
    

此份代码的思想不是为了提供一种新的方法,而是为了说明一个道理: 实现某一种需求的方法有很多,只不过思考一个问题:为什么最后的最后只留下一个成果。因为那是最推荐的方法,而不推荐的方法,也自然有不推荐的理由。
在该份代码中,就是不推荐的方法,因为它里边有很多需要注意,容易犯错误的地方。而这些坑就是我们在日常的代码中,经常会遇到的小bug。

  • 例如:在该份代码中,若该属性为weak,假如不将其进行强引用,则在其从懒加载的代码出去之前就已经释放。因为是局部变量,因此出来{}之后,就直接释放了。
  //不能以关键字作为命名的开头 
  @property (weak, nonatomic) UILabel *OtherLabel;

因此,为了解决上述的问题。需要将其进行强引用,因此需要将其添加到控制器的view上。从而不会进行释放。
故,另一种方式是,直接将属性定义为strong的。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容