一文弄懂ios 视图进入/离开窗口的监听方法:willMoveToWindow:

导语

需求开发中经常要监听某个页面的可见与不可见,例如某个自定义View在可见时要播放动画,当不可见时(例如被其他页面暂时遮挡,或者退出该视图)要暂停动画。常用的监听方法是-[UIView willMoveToWindow:],本文讲介绍该方法的调用时机以及分享作者遇到过的一个隐蔽的坑。

方法简述

- (void)willMoveToWindow:(nullable UIWindow *)newWindow;

newWindow: The window object that will be at the root of the receiver's new view hierarchy. This parameter may be nil.
如果视图将要从可见变为不可见,即:被从主窗口上移除掉,则newWindow为nil
相反,如果视图将要从不可见变为可见,即:即将添加到主窗口上,则newWindow为当前程序的keyWindow

调用时机

从上面的方法简述来看,当view的视图层级的根窗口改变时,就会触发该方法回调。为了更深刻地理解这个方法,我们还需要知道它在view和viewController的整个生命周期中的位置
为了获取整个生命周期,写如下代码来获取日志

// VC的代码
- (void)viewDidLoad{
    NSLog(@"vc[ceshi]viewDidLoad");
    MyView *myView = [[MyView alloc] init];
    MySubView *mySubView = [[MySubView alloc] init];
    [self.view addSubview:myView];
    [myView addSubview:mySubView];
}

获取到的日志如下:


image.png
view和VC的生命周期.png

如上图,展示了view和viewController生命周期中的主要节点。根据日志的打印顺序,图中的箭头表示时间的先后顺序,不一定能够代表调用/触发关系。

  • 当视图被添加到父视图后,会由上至下递归调用willMoveToSuperView:方法,再由下至上递归调用didMoveToSuperView:方法。

  • 在视图即将出现时,即viewWillAppear时,由上至下递归调用willMoveToWindow:方法,再由下至上递归调用didMoveToWindow:方法

  • 此时视图层级已经确定好,然后开始视图布局,在layoutSubViews即将调用前,会触发VC的viewWillLayoutSubviews和viewDidLayoutSubviews方法。
    在视图全部布局完成后,触发viewDidAppear。
    ⚠️注意这里只能根据日志看到时间的先后顺序,看不到「视图布局完成后是如何通过回调触发viewDidAppear的」,官方文档给的注释是当所有过渡动画都完成之后,触发viewDidAppear

    Called after the view has fully transitioned to visible, when any transition animations have completed.

遇到的一个坑

需求开发时,发现在当前页面切换到另一个VC时,willMoveToWindow出现了这样的调用情况
willMoveToWindow:nil
willMoveToWindow:newWindow
willMoveToWindow:nil
视图第一次被从窗口上移除,这是预期内的
然而后面视图又被添加回窗口,然后再次移除,这是预期外的表现。
断点查看第二次调用,即willMoveToWindow:newWindow时的堆栈


image.png

如上图,可以看到底层调用有许多和UINavigationController、aniamtion相关的方法,推测和我们切换VC时的动画有关。
下面是我们切换VC的代码

UINavigationController *navVC = UIApplication.sharedApplication.keyWindow.rootViewController;
[navVC pushViewController:vc animated:**YES**];

我们尝试将YES改为NO,不要切换VC时的过渡动画,果然额外的两次willMoveToWindow的调用没有了。这印证了我们的推测:当pushViewController设置animated为YES 的时候,

  • pushViewController先将当前VC pop出堆栈,此时调用了第一次willMoveToWindow:nil

  • 由于设置了animated为YES,要表现出当前VC的页面动态消失的效果,因而当前VC的视图会再次被添加到当前窗口中,此时调用了第二次的willMoveToWindow:newWindow

  • 当过渡动画结束后,当前VC的视图完全从当前窗口上被移除掉,此时调用了第三次的willMoveToWindow:nil

结论:psuhViewController:animated的过渡动画,会导致willMoveToWindow被额外调用两次

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

推荐阅读更多精彩内容