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实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

CSS3中的字体及相关属性详解

《CSS3中的字体及相关属性详解》:本文主要介绍了CSS3中的字体及相关属性,详细内容请阅读本文,希望能对你有所帮助... 字体网页字体的三个来源:用户机器上安装的字体,放心使用。保存在第三方网站上的字体,例如Typekit和Google,可以link标签链接到你的页面上。保存在你自己Web服务器上的字

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

如何基于Python开发一个微信自动化工具

《如何基于Python开发一个微信自动化工具》在当今数字化办公场景中,自动化工具已成为提升工作效率的利器,本文将深入剖析一个基于Python的微信自动化工具开发全过程,有需要的小伙伴可以了解下... 目录概述功能全景1. 核心功能模块2. 特色功能效果展示1. 主界面概览2. 定时任务配置3. 操作日志演示

JavaScript实战:智能密码生成器开发指南

本文通过JavaScript实战开发智能密码生成器,详解如何运用crypto.getRandomValues实现加密级随机密码生成,包含多字符组合、安全强度可视化、易混淆字符排除等企业级功能。学习密码强度检测算法与信息熵计算原理,获取可直接嵌入项目的完整代码,提升Web应用的安全开发能力 目录

一文教你如何解决Python开发总是import出错的问题

《一文教你如何解决Python开发总是import出错的问题》经常朋友碰到Python开发的过程中import包报错的问题,所以本文将和大家介绍一下可编辑安装(EditableInstall)模式,可... 目录摘要1. 可编辑安装(Editable Install)模式到底在解决什么问题?2. 原理3.

Android与iOS设备MAC地址生成原理及Java实现详解

《Android与iOS设备MAC地址生成原理及Java实现详解》在无线网络通信中,MAC(MediaAccessControl)地址是设备的唯一网络标识符,本文主要介绍了Android与iOS设备M... 目录引言1. MAC地址基础1.1 MAC地址的组成1.2 MAC地址的分类2. android与I