iOS 摸鱼周报 #80 |Developer 设计开发加速器话题,SwiftUI 中管理数据模型
source link: https://zhangferry.com/2022/12/29/iOSWeeklyLearning_80/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
iOS 摸鱼周报 #80 |Developer 设计开发加速器话题,SwiftUI 中管理数据模型
- iOS摸鱼周报
- 2022-12-29
- 本期话题: Developer 设计开发加速器|在 SwiftUI 中管理数据模型
- 本周学习:iOS 堆栈调用理论回顾
- 内容推荐:SwiftUI 好文推荐
- 摸一下鱼:一款个人知识管理工具 MindForger,通过渲染高质量的图像、视频和动画展示数学之美;LearnGPT;洞悉开源趋势的网站:ossinsight.io;Github推文:今年学到了哪些有趣的东西
Developer 设计开发加速器|在 SwiftUI 中管理数据模型
@师大小海腾:SwiftUI 以一种声明式的编程方式来定义用户界面,而这需要由您来定义数据与视图之间的依赖关系,以便能让 SwiftUI 正确工作。通过本次活动,您将了解 SwiftUI 提供的各种工具,用于将 App 的数据连接到用户界面。您还可以深入了解 SwiftUI 框架驱动的原理,以便能让您的 App 正确运作并且拥有良好性能。
活动将于 2023 年 1 月 10 日(周二)举办。名额有限。请在 2023 年 1 月 9 日前报名参加。报名地址: https://developer.apple.com/events/view/D793NQ6482/dashboard。
整理编辑:Hello World
iOS 堆栈调用理论回顾
我们都知道程序的函数调用利用的是栈结构,每嵌套调用一次函数,就执行一次压栈操作,函数执行完毕后,执行出栈操作回到栈底(也就是函数调用处),继续执行后续指令。 大部分操作系统栈的增长方向都是从高往低(包括 iOS / Mac OS),意味着每次函数调用栈开辟都是在做内存地址的减法,Stack Pointer
指向栈顶,Frame Pointer
指向上一个栈帧的 Stack Pointer
的地址值,通过 Frame Pointer
就可以递归回溯获取整个调用栈。 每一次压栈时的数据结构被称为栈帧(Stack Frame),里面存储了当前函数的栈顶指针以及栈底指针,如果我们能拿到每一次压栈的数据结构, 则可以根据这两个指针来递归回溯整个调用栈。
对于 x86_64或者 arm64 架构, 函数调用的汇编指令 call/bl
做法都是类似的:
- 先将函数调用的下一条指令地址入栈,这一条指令是被调用函数执行结束后需要跳转执行的指令,一般存储到
LR
寄存器中。如果后续还有其他函数调用,则会把LR
存入栈帧进行保存。 - 然后保存调用函数
caller
的FP
指针,保存位置紧邻LR
存储的内存地址。 - 开辟新的栈空间,重新赋值
FP
指向新的栈的栈底,即被调用函数的栈帧的栈底。
通过上面的操作,我们已经可以实现串起整个函数调用链。但是由于我们只获取到 LR
的值,它记录的是 caller
函数中的某一条指令地址,而我们的二进制文件存储的都是函数调用的首地址,所以要如何通过 LR
对应到具体的函数是下一步要做的事情。采用的方法也很好理解,即通过遍历 MachO
的符号表,找到每个栈帧中存储的 LR
的值最相近的高地址的函数,认为该函数是 Caller
调用函数。
上面针对的是普通的函数调用,在实际情况下会有一些特殊的函数调用,例如内联或者尾调用等。这些都是没有办法通过上面的方式获取到调用栈的。
另外 x86_64 和 arm64 还有一些不同之处在于,arm64 下编译器可能会做一个优化:即针对叶子节点函数会优化栈帧结构,不再入栈保存 FP
,这时读取到的 FP
指针实际是 Caller
函数的 FP
。
这个优化只针对 FP
指针,叶子节点函数的LR
指针还是会保存的(因为需要出栈继续执行下条指令)。所以我们可以通过线程上下文获取当前的 LR
对比FP
计算得到的LR
是否是同一个地址,来判断最后一次的 FP
是叶子节点函数的 FP
还是它的调用方的 FP
。相同表示未优化 FP
,不同表示已优化,则需要记录本次的 LR
。
具体实现代码可以参考 BSBacktraceLogger,简化的核心代码如下:
NSString *_bs_backtraceOfThread(thread_t thread) {
// 初始化50长度的指针数组
uintptr_t backtraceBuffer[50];
int i = 0;
// ...
const uintptr_t instructionAddress = bs_mach_instructionAddress(&machineContext);
backtraceBuffer[i] = instructionAddress;
++i;
// 通过线程上下文获取 LR 地址
uintptr_t linkRegister = bs_mach_linkRegister(&machineContext);
if(instructionAddress == 0) {
return @"Fail to get instruction address";
}
// 自定义的帧实体链表, 存储上一个调用栈以及返回地址(lr)
BSStackFrameEntry frame = {0};
// fp指针
const uintptr_t framePtr = bs_mach_framePointer(&machineContext);
if(framePtr == 0 ||
// 将fp存储的内容 (pre fp指针)存储到previous, fp+1 存储的内容(lr)存储到return_address
bs_mach_copyMem((void *)framePtr, &frame, sizeof(frame)) != KERN_SUCCESS) {
return @"Fail to get frame pointer";
}
// lr和fp读取的数据不相等, 是因为arm64下 编译器做的优化处理,即叶子函数复用调用函数的调用栈fp, 但是lr和sp是没有复用的, 所以为了避免丢帧,使用lr填充
if (linkRegister != 0 && frame.return_address != linkRegister) {
backtraceBuffer[i] = linkRegister;
i++;
}
// 原理就是通过当前栈帧的fp读取下一个指针数据,记录的是上一个栈帧的fp数据, fp + 2,存储的是lr数据, 即当前栈退栈后的返回地址(bl的下一条指令地址)
for(; i < 50; i++) {
backtraceBuffer[i] = frame.return_address;
// ... 容错处理
}
// 开始符号化,这里就是文中说的通过 lr 获取最近的函数首地址进行符号化
int backtraceLength = i;
Dl_info symbolicated[backtraceLength];
bs_symbolicate(backtraceBuffer, symbolicated, backtraceLength, 0);
// ... 打印结果
return [resultString copy];
}
代码中的 if (linkRegister != 0 && frame.return_address != linkRegister)
片段 BSBacktraceLogger
中是没有的,当根据打印堆栈将调用栈数调整到恰好 50 个时,会发现最后一个叶子节点函数栈帧丢失,也就是文中说的针对 arm64的优化。
以上代码仅是 FP
和 LR
的递归回溯的实现,符号化部分参考函数 bs_symbolicate()
。
也可以查看 BSBacktraceLogger
的 fork 版本代码,增加了核心代码逻辑注释方便学习。
整理编辑:@远恒之义
1、SwiftUI 与 Core Data —— 安全地响应数据 -- 来自:东坡肘子
@远恒之义:保证应用不因 Core Data 的原因导致意外崩溃是对开发者的起码要求。本文将介绍可能在视图中产生严重错误的原因,如何避免,以及在保证视图对数据变化实时响应的前提下如何为使用者提供更好、更准确的信息。
2、如何使用 SwiftUI Grid API 创建网格布局 -- 来自:Simon Ng
@远恒之义:Grid 视图是一种容器视图,它以二维布局排列其他视图,Grid 为开发人员提供了构建基于网格的布局的更多选项。你可以使用 HStack 和 VStack 来构建类似的布局,不过 Grid 视图可以为你节省大量代码并使你的代码可读性更高,你可以尝试使用 Grid 来构建一些有趣的布局。
3、如何对 SwiftUI list 中的列表行进行重新排序 -- 来自:sarunw
@远恒之义:想要启用 SwiftUI 列表行重新排序,你只需执行以下步骤即可:创建数据源(必须是可变的)、使用填充列表视图 ForEach
、将 onMove(perform:)
修饰符应用于 ForEach
、手动移动项目 onMove
的闭包,调用方法十分简单方便。
4、如何创建 iOS 锁屏小部件? -- 来自:Lee Kah Seng
@远恒之义:在 iOS 16 中,Apple 新增了锁定屏幕,其中锁屏小组件带来 app 新的曝光入口。与桌面小组件类似,锁屏小组件主要用 WidgetKit 来实现功能。不同的是,Apple 引入了 3 个新的不同类型的锁屏小组件:accessoryCircular
、accessoryRectangular
和 accessoryInline
,前两个为小与中两种尺寸,后者为单行文本。
5、用 SwiftUI 实现 AI 聊天对话 app - iChatGPT -- 来自掘金:37手游iOS技术运营团队
@远恒之义:iChatGP 是一款用 SwiftUI 实现的开源 ChatGPT app,支持系统 iOS 14.0+、iPadOS 14.0+、macOS 11.0+,目前已实现 ChatGPT 基本聊天功能:直接与 ChatGPT 对话,并且保留上下文;复制问题和回答内容;快捷重复提问。
6、EBPF 介绍 -- 来自:酷壳
@远恒之义:eBPF(extened Berkeley Packet Filter)是一种内核技术,它允许开发人员在不修改内核代码的情况下运行特定的功能。eBPF 比起传统的 BPF 来说,传统的 BPF 只能用于网络过滤,而 eBPF 则可以用于更多的应用场景,包括网络监控、安全过滤和性能分析等。耗子叔在文末留了一个彩蛋,聊了聊他对大火的 ChatGPT 一些看法。
整理编辑:师大小海腾
1、A Tour in the Wonderland of Math with Python 通过渲染高质量的图像、视频和动画来展示数学之美。
2、MindForger,是一款个人知识管理工具
MindForger的目标是模仿人类的思维--学习、回忆、识别、联想、遗忘--以实现与你的思维的协同,使你的搜索、阅读和写作更有效率。
不仅如此,MindForger 尊重隐私,并确保知识安全。
不仅仅是一个markdown 编辑器,更是一个辅助的智能助手。
3、LearnGPT:ChatGPT 是一个非常强大的工具,但对于它能做什么我们大多数情况还是随便想一些问题或者通过其他人发的测试样例进行了解。为了大家更方便了解 ChatGPT,这个网站专门收集了跟 ChatGPT 对话产生的有意思的问题。
4、Open Source Software Insight:一个洞悉开源软件的网站,从非常多的维度总结了当前开源软件的趋势,还可以以数据视角去了解仓库和开发者的各类信息,主要数据来源为 Github。
5、Twitter - 今年你阅读过的,或者学习到的最有趣的内容是什么:来自 Github 官方推文,评论区有很多优质的内容。
iOS 摸鱼周报,主要分享开发过程中遇到的经验教训、优质的博客、高质量的学习资料、实用的开发工具等。周报仓库在这里:https://github.com/zhangferry/iOSWeeklyLearning ,如果你有好的的内容推荐可以通过 issue 的方式进行提交。另外也可以申请成为我们的常驻编辑,一起维护这份周报。另可关注公众号:iOS成长之路,后台点击进群交流,联系我们,获取更多内容。
iOS 摸鱼周报 #79 | Freeform上线 & D2 本周开始
iOS 摸鱼周报 #78 | 用 ChatGPT 做点好玩的事
Recommend
-
72
-
62
我喜欢读书,而且读的很快。本人一直在研究学习方法,学习能力还在高峰。我尤其喜欢主题式阅读,根据重点,详略有别。其实就是,一段时间集中的研究一类资料,它们的内容可以相互补充、印证,重复的内容当成复习。 这篇就当成最近研究网站架构问题的一个小小的总结...
-
119
写在前面GitDataV,是一个github“大数据可视化平台”,通过它你可以更直观的看到你在github里的一些数据,(之所以打双引号,是因为我觉得这个还没到大数据可视化的程度)。其实我在 上篇文章 分享的时候已经提到了这个想法,通过gi
-
51
6月5日,美国科技巨头苹果宣布,在中国设立首个设计开发加速器,专门为iOS、iPadOS、watchOS、macOS 和tvOS app开发者提供支持。该设计开发加速器将于今年夏天在上海开放,为大中华区成千上万的开发者提供有关app设计与开发的专业培训和资源。
-
41
2016年起,中国遥感卫星发射量连续两年增速达到100%,已经步入航天密集发射期。
-
32
【51CTO.com快译】如今我们所浏览的网站,除了基本的信息展示之外,大多数具有生动的动画、多样的布局、以及诱人的互动元素,多要归功于CSS创新技术的实现。截至到去年年底,Flexbox已经被运用到了Google Chrome的83%加载页面上(请参阅:...
-
19
原标题格力电器:子公司设计开发的芯片已有数千万颗的使用量证券时报e公司讯,格力电器7月28日在互动平台表示,公司在芯片研发领域已深耕多年,在2018年设立全资子公司珠海零边界集成电路有限公司,专注设计开发空调等家电的主控芯片和功率器件芯片,
-
10
站在VR世界的大门前 - 项目特质与设计开发流程的策略选择 今日,距离这个博客建成上线,已是整整五年的时间。尝试边听Tupac边做博客,再一次...
-
3
本期话题: Developer 设计开发加速器|探索 Create ML Components本周学习:解决使用 AVAudioRecorder 录音保...
-
5
早上好呀,又到了元气满满的周五!来看看这周发生了什么吧~ 11月27日消息,日前,迅雷网游加速器发布停运通知,称由于平台运营策略调整,结合整体运营情况考虑,迅雷网游加速器将于2022年12月1日正式停运,关停加速服务和各类活动。 11月2...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK