Instrument和Tools
- @warn_unqualified_access
- 对PreView 设置不同的调试尺度
- 怎样查找那些数据更改导致SwiftUI视图更新
- 怎样运用Instrument分析SwiftUI代码并辨认缓慢布局
概述
文章首要共享SwiftUI Modifier的学习进程,将运用案例的方法进行阐明。内容深入浅出,Instruments和Tools首要表达东西运用,首要是对进程进行探求,可以移步Github下载code -> github案例链接
1、怎样使SwiftUI修饰符与@warn_unqualified_access一起运用更安全。
每个SwiftUI都会在某些时分犯相同的差错,并且会不止一次犯这种差错:将.someModifier()写成someModifier(),导致程序出现EXC_BAD_ACCESS。解决方案是用Swift的@warn_unqualified_access
特色,这意味着假设不运用变量名或类似称谓,则无法访问特色和方法。
创建titleStyle()
//扩展一个titleStyle()方法,向视图添加一些修饰符以使其匹配子弟你主题,那么将@warn_unqualified_access在方法签名之前运用。
extension View {
@warn_unqualified_access
func titleStyle() -> some View {
self
.font(.largeTitle)
.fontWeight(.black)
.padding()
.background(.blue)
.foregroundStyle(.white)
.cornerRadius(10)
}
}
详细运用情况
struct FFToolingSafe: View {
var body: some View {
//当运用它是,正常情况下
Text("Meta BBLv")
.titleStyle()
//异常情况,删去掉了.
Text("Meta BBLv Error")
titleStyle()
}
}
这产生了差异,首要这是一个不合格的访问,我没有声明titleStyle()在哪里调用。所以SwiftUI假设我实际上FFToolingSafe在调用他。这意味着实际上正在调用self.padding(),因此会出现内存激增,导致出现一个无限递归视图并毕竟溃散。
SwiftUI的规则是不运用@warn_unqualified_access作用在自己的修饰符上,但是我们可以为自己构建的自定义修饰符添加它,假设出现了运用差错的情况下(比如删去了".")
,这个时分SwiftUI会为你添出提示:
- Use of ‘titleStyle’ treated as a reference to instance method in protocol ‘View’
- Use ‘self.’ to silence this warning
Xcode贴图
2、对PreView 设置不同的调试尺度
构建程序时,要对全部的支撑机型进行匹配,防止出现不同屏幕间的size差异。比如在大一些的屏幕(iPhone 14 Pro Max)上面布局是OK的,下放到小一些的屏幕(iPhone 14 Pro)出现问题。在SwiftUI中,全部组件自身都习惯Dynamic Type Size,这是非常完美的,但是假设你想在Preview中也想要预览不同size又该怎样操作呢?
Xcode 14
在Xcode 14的版别中,关于preview的设置还可以添加.environment(\.sizeCategory, .extraSmall)
来设定多预览。在Xcode 14从前的版别不知道详细情况怎样,未研讨SwiftUI。
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
.environment(\.sizeCategory, .extraSmall)
}
}
}
Xcode Version 15.0 beta 8 (15A5229m)
在此版别中,因为Swift现已添加了宏的相关内容,目前Preview经过宏来完结的。
经过检验,当想要在Xcode15中预览多个画面,也可设置多个宏。无法在#Preview
下声明任何特色,和运用上述的方法。
#Preview {
FFToolingDiffenertSize()
}
#Preview("Meta BBLv") {
FFToolingDiffenertSize()
}
运用方法也愈加简洁,更改为可视化操作
Xcode操作贴图
3、怎样查找那些数据更改导致SwiftUI视图更新
SwiftUI供应了一个特别的、仅供调试的方法,可以运用它来辨认导致视图从头加载自身的更改。该方法专门用于调试,不应在body实际程序中声明。但是在check视图正在重复调用特色还不承认原因时运用。
该方法是Self._printChanges()
,并且应在特色内部调用。这意味着你或许暂时需求添加闪现返回来发挥惯例的代码视图。
class EvilStateObject: ObservableObject {
var timer: Timer?
init() {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
if Int.random(in: 1...5) == 1 {
self.objectWillChange.send()
}
})
}
}
extension ShapeStyle where Self == Color {
static var random: Color {
Color(
red: .random(in: 0...1),
green: .random(in: 0...1),
blue: .random(in: 0...1)
)
}
}
struct FFToolingSwiftUIChange: View {
@StateObject private var eviObject = EvilStateObject()
var body: some View {
let _ = Self._printChanges()
//经过设置背景色可以直观的查询body视图特色何时被调用。现象是假设Body被多次调用,那么视图背景色也会改动多次
Text("META BBLV")
.background(.random)
}
}
监督视图的改写
4、怎样运用Instrument分析SwiftUI代码并辨认缓慢布局
Xcode的Instruments
东西附带了一组超卓的SwiftUI分析功用,使我们可以承认视图重回的频率、核算视图主体缓慢的次数,甚至情况在实时改动的情况。
创建检验条件
创建一个每0.01秒触发一次的计时器,并有一个闪现随机值UUID的视图和一个button
class FrequentUdater: ObservableObject {
var timer: Timer?
init() {
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true, block: { _ in
self.objectWillChange.send()
})
}
}
检验ContentView
代码非常简单,有一个每0.01s就触发的Timer,动态切换UUID,一起创建了一个Button,点击时tapCount+1
struct FFToolingInstruments: View {
@StateObject private var updater = FrequentUdater()
@State private var tapCount = 0
var body: some View {
VStack {
Text("\(UUID().uuidString)")
Button("Tap count: \(tapCount)") {
tapCount += 1
}
}
}
}
检验进程
默许情况下,SwiftUI东西会告知我们许多数据:
- 在此期间创建了多少视图以及创建它们所用的时间(View Body)
- 视图的特色是什么以及它们怎样随时间改动(View Properties)
- 产生了多少次核心动画commit( Core Animation Commits)
- 每个函数调用详细花费了多少时间(Time Profiler)
这些东西都可以协助确诊和解决SwiftUI应用程序中的功用问题。
View Body
当选择针对View Body进行探求时,Instroments将效果分解为SwiftUI和我自己的项目,前者是原始类型(如文本按钮等),后者是我的自定义类型视图。在我的例子中,“FFToolingInstruments”是我的自定义视图
在此区域,重要的是Count数据以及均匀持续时间(每个事物被创建了多少次以及花费的时长)。我这儿做的是一个0.01的Timer,我暂时将它当作一个压力检验,这样会看到非常高的count,因为布局非常简单,在上面效果看来。均匀创建时间是微秒
等级。
View Properties(跟踪情况改动)
选择View Properties,这儿闪现了全部视图的全部特色,包含当时的值和全部从前的值。因为我为程序添加了一个Button,就是用来调试这儿的,每次点击都会使tapCount+1。查找State<Int>
的Property Type。这儿有一个小技巧,当你选择停止检验的时分,在时间轴的最后会有一个倒三角图形的时间线符号,拖动这根时间线,就可以看见你在检验进程中的tapCount跟着Button点击+1的作用了。
Core Animation Commits(辨认慢速制作)
在SwiftUI中,可以直接运用Metal来提高功用,但大多数时分SwiftUI都运用Core Animation进行烘托。运用Instroments内置的Core Animation分析东西可以对其进行分析。当多个更改一起放入一个事物时,core Animation作用最佳。可以在一个 事物中有用的堆叠一系列的作业,再要求CA继续烘托,那么这个进程称为commit事物。
因此,当Instruments向我标明Core Animation的commit时,这代表着很昂贵的价值,我无法描绘,就像Ben老头讲的dirty memory一个道理,这儿是一个dirty commit。它真正向我们展现的是SwiftUI因为更新而被逼从头制作屏幕上的像素的次数。理论上,只有当App的实际情况导致不同的视图层次结构时,才会产生这种情况,因为SwiftUI应该可以将body特色的新输入与旧输出进行比较。
Time Profiler(查找用时较长的函数)
Time Profiler精确的向我闪现了代码每个部分花费多少时间。这与Instruments中惯例时间分析器的作业原理相同。
- 默许情况下,右侧扩展的详细信息窗口闪现最重要的库房跟踪,
- 在左面,可以看到全部的线程,以及可让你深入了解它们调用的函数以及这些函数的公开指示器。
- 可以对“Call Tree”进行过滤,选择“Hide System Libraries”可以隐藏系统库,这是才智闪现我自己编写的代码。
- 还可以对“Call Tree”进行再次过滤,选择“invert Call Tree”进行树的回转,以便更清晰的检查函数。