iOS开发-ViewController的生命周期相关

2023-11-29 18:32

本文主要是介绍iOS开发-ViewController的生命周期相关,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • ViewController生命周期
    • 加载流程
    • didReceiveMemoryWarning
  • View的layoutSubviews
    • Runloop相关
  • view的drawRect:方法

ViewController生命周期

加载流程

在这里插入图片描述

1.init或者initWithCoder:(NSCoder *)aDecoder:(如果使用storyboard或者xib)
2.loadView:加载view
3.viewDidLoad:view加载完毕
4.viewWillAppear:控制器的view将要显示
5.viewWillLayoutSubviews:控制器的view将要布局子控件
6.viewDidLayoutSubviews:控制器的view布局子控件完成
这期间系统可能会多次调用viewWillLayoutSubviews、viewDidLayoutSubviews俩个方法7.viewDidAppear:控制器的view完全显示
8.viewWillDisappear:控制器的view即将消失的时候
这期间系统也会调用viewWillLayoutSubviews 、viewDidLayoutSubviews 两个方法9.viewDidDisappear:控制器的view完全消失的时候

didReceiveMemoryWarning

Discussion Your app never calls this method directly. Instead, this
method is called when the system determines that the amount of
available memory is low.

You can override this method to release any additional memory used by
your view controller. If you do, your implementation of this method
must call the super implementation at some point.

当app收到内存警告的时候会发消息给视图控制器。
app从来不会直接调用这个方法,而是当系统确定可用内存不足的时候采取调用。
如果你想覆写这个方法来释放一些控制器使用的额外内存,你应该在你的实现方法中调用父类的实现方法。

参考文章
https://blog.csdn.net/wangyanchang21/article/details/50730902
https://developer.apple.com/documentation/uikit/uiviewcontroller/1621409-didreceivememorywarning?language=objc


View的layoutSubviews

  1. init初始化不会触发layoutSubviews
  2. addSubview会触发layoutSubviews
  3. 改变一个UIViewframe会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。
  4. 滚动一个UIScrollView引发UIView的重新布局会触发layoutSubviews
  5. 旋转Screen会触发父UIView上的layoutSubviews事件。
  6. 直接调用setNeedsLayout 或者 layoutIfNeeded

Runloop相关

在非主页面加载时

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1* frame #0: 0x0000000100529264 GSWatermarkView`-[GSWaterMarkView layoutSubviews](self=0x000000011d801410, _cmd="layoutSubviews") at GSWaterMarkView.m:110frame #1: 0x00000001a77db5b0 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2156frame #2: 0x00000001a2fe7af0 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 68frame #3: 0x00000001a9d81c0c QuartzCore`-[CALayer layoutSublayers] + 292frame #4: 0x00000001a9d81f14 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 484frame #5: 0x00000001a9d953fc QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 140frame #6: 0x00000001a9cda184 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double) + 296frame #7: 0x00000001a9d05228 QuartzCore`CA::Transaction::commit() + 684frame #8: 0x00000001a7362d6c UIKitCore`_afterCACommitHandler + 144frame #9: 0x00000001a324bf5c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36frame #10: 0x00000001a3246bfc CoreFoundation`__CFRunLoopDoObservers + 420frame #11: 0x00000001a32471ac CoreFoundation`__CFRunLoopRun + 1292frame #12: 0x00000001a3246978 CoreFoundation`CFRunLoopRunSpecific + 480frame #13: 0x00000001ad376534 GraphicsServices`GSEventRunModal + 108frame #14: 0x00000001a7338f0c UIKitCore`UIApplicationMain + 1940frame #15: 0x000000010052814c GSWatermarkView`main(argc=1, argv=0x000000016f8df940) at main.m:14frame #16: 0x00000001a30c6f04 libdyld.dylib`start + 4

在初始界面加载时

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1* frame #0: 0x0000000100b05264 GSWatermarkView`-[GSWaterMarkView layoutSubviews](self=0x000000010130f210, _cmd="layoutSubviews") at GSWaterMarkView.m:110frame #1: 0x00000001a77db5b0 UIKitCore`-[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 2156frame #2: 0x00000001a2fe7af0 libobjc.A.dylib`-[NSObject performSelector:withObject:] + 68frame #3: 0x00000001a9d81c0c QuartzCore`-[CALayer layoutSublayers] + 292frame #4: 0x00000001a9d81f14 QuartzCore`CA::Layer::layout_if_needed(CA::Transaction*) + 484frame #5: 0x00000001a9d953fc QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 140frame #6: 0x00000001a9cda184 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double) + 296frame #7: 0x00000001a9d05228 QuartzCore`CA::Transaction::commit() + 684frame #8: 0x00000001a7350d20 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 84frame #9: 0x00000001a324c95c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28frame #10: 0x00000001a324c0e0 CoreFoundation`__CFRunLoopDoBlocks + 268frame #11: 0x00000001a32470e0 CoreFoundation`__CFRunLoopRun + 1088frame #12: 0x00000001a3246978 CoreFoundation`CFRunLoopRunSpecific + 480frame #13: 0x00000001ad376534 GraphicsServices`GSEventRunModal + 108frame #14: 0x00000001a7338f0c UIKitCore`UIApplicationMain + 1940frame #15: 0x0000000100b0414c GSWatermarkView`main(argc=1, argv=0x000000016f303940) at main.m:14frame #16: 0x00000001a30c6f04 libdyld.dylib`start + 4

可以看出在app启动时,初始界面View的layoutSubviews__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__触发,后续的界面由__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__触发


view的drawRect:方法

  1. 直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect大小不能为0。
  2. drawRect的调用时机是在viewWillAppearviewDidAppear之间。且在ViewlayoutSubviews之后
2020-03-03 14:05:58.384185+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController loadView]]
2020-03-03 14:05:58.384252+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidLoad]]
2020-03-03 14:05:58.385593+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView didMoveToSuperview]]
2020-03-03 14:05:58.385686+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewWillAppear:]]
2020-03-03 14:05:58.387915+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewWillLayoutSubviews]]
2020-03-03 14:05:58.387956+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidLayoutSubviews]]
2020-03-03 14:05:58.387975+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView layoutSubviews]]
2020-03-03 14:05:58.388046+0800 GSWatermarkView[1318:1216023]  GSWaterMarkView [-[GSWaterMarkView drawRect:]]
2020-03-03 14:05:58.427785+0800 GSWatermarkView[1318:1216023]  ViewController [-[ViewController viewDidAppear:]]
  1. 调用sizeToFit,会触发drawRect的调用。
  2. 通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:

app启动时,添加到初始界面的堆栈,还是CALayer触发

* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1* frame #0: 0x00000001042e531c GSWatermarkView`-[GSWaterMarkView drawRect:](self=0x0000000104910450, _cmd="drawRect:", rect=(origin = (x = 0, y = -0.125), size = (width = 374, height = 210.5))) at GSWaterMarkView.m:115frame #1: 0x00000001a77da8c0 UIKitCore`-[UIView(CALayerDelegate) drawLayer:inContext:] + 608frame #2: 0x00000001a9d83d78 QuartzCore`-[CALayer drawInContext:] + 312frame #3: 0x00000001a9c4f9e8 QuartzCore`CABackingStoreUpdate_ + 180frame #4: 0x00000001a9d84ce0 QuartzCore`___ZN2CA5Layer8display_Ev_block_invoke + 56frame #5: 0x00000001a9cd6f64 QuartzCore`x_blame_allocations + 148frame #6: 0x00000001a9d847b0 QuartzCore`-[CALayer _display] + 1652frame #7: 0x00000001a9d9551c QuartzCore`CA::Layer::layout_and_display_if_needed(CA::Transaction*) + 428frame #8: 0x00000001a9cda184 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double) + 296frame #9: 0x00000001a9d05228 QuartzCore`CA::Transaction::commit() + 684frame #10: 0x00000001a7350d20 UIKitCore`__34-[UIApplication _firstCommitBlock]_block_invoke_2 + 84frame #11: 0x00000001a324c95c CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 28frame #12: 0x00000001a324c0e0 CoreFoundation`__CFRunLoopDoBlocks + 268frame #13: 0x00000001a32470e0 CoreFoundation`__CFRunLoopRun + 1088frame #14: 0x00000001a3246978 CoreFoundation`CFRunLoopRunSpecific + 480frame #15: 0x00000001ad376534 GraphicsServices`GSEventRunModal + 108frame #16: 0x00000001a7338f0c UIKitCore`UIApplicationMain + 1940frame #17: 0x00000001042e414c GSWatermarkView`main(argc=1, argv=0x000000016bb23940) at main.m:14frame #18: 0x00000001a30c6f04 libdyld.dylib`start + 4

参考文章
https://segmentfault.com/a/1190000018645601
https://www.jianshu.com/p/4edfd23ca49a

这篇关于iOS开发-ViewController的生命周期相关的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/433877

相关文章

一文详解Python如何开发游戏

《一文详解Python如何开发游戏》Python是一种非常流行的编程语言,也可以用来开发游戏模组,:本文主要介绍Python如何开发游戏的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录一、python简介二、Python 开发 2D 游戏的优劣势优势缺点三、Python 开发 3D

基于Python开发Windows自动更新控制工具

《基于Python开发Windows自动更新控制工具》在当今数字化时代,操作系统更新已成为计算机维护的重要组成部分,本文介绍一款基于Python和PyQt5的Windows自动更新控制工具,有需要的可... 目录设计原理与技术实现系统架构概述数学建模工具界面完整代码实现技术深度分析多层级控制理论服务层控制注

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

基于Go语言开发一个 IP 归属地查询接口工具

《基于Go语言开发一个IP归属地查询接口工具》在日常开发中,IP地址归属地查询是一个常见需求,本文将带大家使用Go语言快速开发一个IP归属地查询接口服务,有需要的小伙伴可以了解下... 目录功能目标技术栈项目结构核心代码(main.go)使用方法扩展功能总结在日常开发中,IP 地址归属地查询是一个常见需求:

基于 Cursor 开发 Spring Boot 项目详细攻略

《基于Cursor开发SpringBoot项目详细攻略》Cursor是集成GPT4、Claude3.5等LLM的VSCode类AI编程工具,支持SpringBoot项目开发全流程,涵盖环境配... 目录cursor是什么?基于 Cursor 开发 Spring Boot 项目完整指南1. 环境准备2. 创建

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

Maven中生命周期深度解析与实战指南

《Maven中生命周期深度解析与实战指南》这篇文章主要为大家详细介绍了Maven生命周期实战指南,包含核心概念、阶段详解、SpringBoot特化场景及企业级实践建议,希望对大家有一定的帮助... 目录一、Maven 生命周期哲学二、default生命周期核心阶段详解(高频使用)三、clean生命周期核心阶

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

基于Java开发一个极简版敏感词检测工具

《基于Java开发一个极简版敏感词检测工具》这篇文章主要为大家详细介绍了如何基于Java开发一个极简版敏感词检测工具,文中的示例代码简洁易懂,感兴趣的小伙伴可以跟随小编一起学习一下... 目录你是否还在为敏感词检测头疼一、极简版Java敏感词检测工具的3大核心优势1.1 优势1:DFA算法驱动,效率提升10