SwiftUI|一种自定义 macOS TabView 的方案

介绍一种在 SwiftUI 里实现自定义 TabView 的方法(macOS)

Share
SwiftUI|一种自定义 macOS TabView 的方案
Photo by Penfer / Unsplash

目前在 macOS 上,SwiftUI 的 TabView 是利用 AppKit 的 NSTabView 实现的。NSTabView 的默认样式带有边框和背景色,顶部 tab 切换使用 NSSegmentedControl 实现,无法满足特定设计需求。

NSTabView 图源:http://www.skyfox.org/cocoa-nstabview.html

网上有一些利用 SwiftUI 基础视图自己实现 tabbar 的方案。这些方案本质上不依赖 TabView 或 NSTabView 实现,只是做了一个模拟切换 tab 的视图,然后在 tab 切换时利用 SwiftUI 的渲染特性,在 body 里面返回对应 tab 的 View。这种方案有一个缺点——每次回到某个 tab 时,对应的 View 会被重新创建。如果页面结构简单的话,这种方案可取;但是对于复杂的页面,每次重新创建的性能开销还是很大的,就不能采用这种方案了。

所以自定义 TabView 最好还是基于原生的 TabView/NSTabView 组件实现。原生组件是不会在切到某个 tab 时重新创建对应的 View 或页面的。

在 AppKit/Cocoa 时代,大家也有这种自定义 TabView 的需求。当时有前辈给出了一种方案:通过修改 NSTabView 的 tabViewType 隐藏它的 tabbar 和边框;然后在 NSTabView 上方添加一个自定义的切换 tab 的视图即可。这个方案在 SwiftUI 上也可以使用,也是本篇文章要介绍的方案。

将 NSTabView 的 tabViewType 设置为 noTabsNoBorder ,可以隐藏 NSTabView 的 tabbar 和边框。目前 SwiftUI 的 TabView 还不支持直接修改 tabViewType ,我们需要借助 SwiftUIIntrospect 来间接获取到 TabView 底层使用的 NSTabView。

TabView(selection: $selectedIndex,
        content:  {
    //...
})
.tabViewStyle(.automatic)
.backgroundStyle(.clear)
.introspect(.tabView, on: .macOS(.v14, .v15)) { tabView in
    tabView.tabViewType = .noTabsNoBorder
}

然后在 TabView 上方添加一个自定义的 tab 切换视图。这个自定义视图可以是利用 SwiftUI 基础视图自己实现的 tabbar,也可以图省事直接用 Picker(segmented 样式的)。

Picker("", selection: $selectedIndex) {
    ForEach(tabNames.indices, id: \.self) { nameIndex in
        Text(tabNames[nameIndex])
    }
}
.pickerStyle(.segmented)

定义一个 Int 类型的状态变量连接 TabView 和 Picker。

@State private var selectedIndex = 0

这样切换 Picker 选项时,TabView 也会切换到对应的页面。

Read more

在 AI 时代,做 iOS 逆向分析有哪些高效手段

在 AI 时代,做 iOS 逆向分析有哪些高效手段

AI 发展如此迅猛,传统的代码手艺活已经被 AI 取代了很大一部分。除了生成代码外,AI 在其他的研发流程也能提升很多效率,例如这次要说的 AI 逆向分析。 在手工时代,我们逆向分析一个 iOS app,通常是使用 Hopper 或者 IDA 等软件查看解密的 Mach-O,然后利用软件提供的能力加上人工去分析逻辑流程。这个过程还要求我们懂一些基础的汇编语法。有时候还要去猜测哪些类哪些方法是负责某个逻辑,靠试验去验证。 现在来到了大模型时代,AI 不仅能自己通过一些简单的工具去分析 ipa 和 Mach-O ,也能使用更准更稳的 MCP、Skill 工具来做深度的分析。 Hopper MCP Hopper 在新版本支持了 MCP Server。 把 framework、Mach-O 或者解密后的 IPA 直接丢给它,

By Gray
Cinder:基于 Swift Macro 与 Mach-O Section 的解耦注册机制

Cinder:基于 Swift Macro 与 Mach-O Section 的解耦注册机制

Cinder(Github) 是一个无需逐模块启动注册、支持字符串、类型和函数调用的 Swift 编译期注册框架。 Cinder 是什么 在 iOS app 里借助 Mach-O 注册能力做一些二进制的插桩操作并不罕见。以往这些操作大都使用 objc runtime ,借助 __attribute__((used)) 和 __attribute__((section("name"))) 实现。在 Swift 上实现有一些难度,因为 Swift runtime 能力弱,以及早期的版本没有类似 objc 的 __attribute__ 能力。 * 在 Swift 5.10 版本,Apple 提供了 @_used 和

By Gray