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

相关文章

基于 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

Python开发简易网络服务器的示例详解(新手入门)

《Python开发简易网络服务器的示例详解(新手入门)》网络服务器是互联网基础设施的核心组件,它本质上是一个持续运行的程序,负责监听特定端口,本文将使用Python开发一个简单的网络服务器,感兴趣的小... 目录网络服务器基础概念python内置服务器模块1. HTTP服务器模块2. Socket服务器模块

Java 与 LibreOffice 集成开发指南(环境搭建及代码示例)

《Java与LibreOffice集成开发指南(环境搭建及代码示例)》本文介绍Java与LibreOffice的集成方法,涵盖环境配置、API调用、文档转换、UNO桥接及REST接口等技术,提供... 目录1. 引言2. 环境搭建2.1 安装 LibreOffice2.2 配置 Java 开发环境2.3 配

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3