SwiftUI 6.0(Xcode 16)全新 @Entry 和 @Previewable 宏让开发妙趣横生

概览

如火如荼的 WWDC 2024 已进入第五天,苹果开发平台中众多海量新功能都争先恐后的喷薄欲出。

在这里就让我们从中挑两个轻松有趣的新功能展示给小伙伴们吧:它们分别是 全新的 @Entry 和 @Previewable 宏。

在本篇博文中,您将学到如下内容:

  • 概览
  • [1. 用 @Entry 宏简化环境变量定义](#1. 用 @Entry 宏简化环境变量定义)
  • [2. @Previewable 让 Xcode 预览调试安闲自得](#2. @Previewable 让 Xcode 预览调试安闲自得)
  • 总结

读完本篇后,相信小伙伴们一定会对全新的 @Entry 和 @Previewable 宏相见恨晚!

那还等什么呢?马上和大熊猫侯佩 一起开始 WWDC24 大冒险吧!

Let's go!!!😉


1. 用 @Entry 宏简化环境变量定义

在 SwiftUI 6.0(iOS 18)之前,要想自己创建自定义环境变量需要以下 3 步。

首先,我们需要创建环境变量类型:

swift 复制代码
enum SuperPower: CustomStringConvertible {
    case timeStop
    case invisibility
    case predictTheFuture
    case immortal
    case teleportation
    
    var description: String {
        switch self {
        case .immortal:
            "永生"
        case .invisibility:
            "隐身"
        case .predictTheFuture:
            "预知未来"
        case .timeStop:
            "时间停止"
        case .teleportation:
            "瞬间移动"
        }
    }
}

接着,我们需要创建环境变量对应的键(EnvironmentKey):

swift 复制代码
struct HideSuperPower: EnvironmentKey {
    static var defaultValue: SuperPower = .immortal
}

最后,我们还需要扩展 EnvironmentValues 以便插入我们的环境变量:

swift 复制代码
extension EnvironmentValues {
    var hideSuperPower: SuperPower {
        get { self[HideSuperPower.self] }
        set { self[HideSuperPower.self] = newValue }
    }
}

为 SwiftUI 增加环境变量这点小事都要如此地大费周章,这不禁让我们这些秃头码农们唏嘘不已。

好消息来了!从 SwiftUI 6.0 开始仅用全新的 @Entry 宏我们即能蜻蜓点水似得创建自定环境变量了。

有了 @Entry 宏,之前那几坨代码现在可以如此这般简化了:

swift 复制代码
extension EnvironmentValues {
    @Entry var hideSuperPower: SuperPower = .immortal
}

是不是养眼了不少?

但是不管如何,使用 hideSuperPower 环境变量的方式还和以前是一毛一样滴:

swift 复制代码
struct ContentView: View {
    
    @Environment(\.hideSuperPower) var power
    
    var body: some View {
        NavigationStack {
            VStack {
                Text("当前超能力:\n\(Text("#\(power)#").foregroundStyle(.red.gradient))")
                    .font(.system(size: 55, weight: .heavy))
                    .foregroundStyle(.gray)
            }
            .navigationTitle("超能力大冒险")
            .toolbar {
                Text("大熊猫侯佩 @ \(Text("CSDN").foregroundStyle(.red))")
                    .font(.headline.weight(.bold))
                    .foregroundStyle(.gray)
            }
        }
    }
}

代码运行效果如下图所示:

@Entry 宏不仅能够用在环境变量的定义中,它同样可以用来简化 Transaction Values、Container Values 以及 Focused Values 等类型的定义:

swift 复制代码
extension Transaction {
    @Entry var myCustomValue: String = "Default value"
}

extension ContainerValues {
    @Entry var myCustomValue: String = "Default value"
}

extension FocusedValues {
    @Entry var myCustomValue: String?
}

更多 @Entry 的"玩法"请小伙伴们移步苹果开发者官网恣意研究。

2. @Previewable 让 Xcode 预览调试安闲自得

除了苹果各个开发框架的重磅更新以外,每年的 WWDC 也都会让果粉必备的开发集成环境 Xcode 如日方升,今年的 WWDC 24 自然也不例外。

我们知道 Xcode 中预览(Preview)和 SwiftUI 的界面调试真何谓是"天作之合"。不过 SwiftUI 6.0 之前,如果我们希望在预览中调试需要传入额外状态的视图就会变得"捉襟见肘":

swift 复制代码
struct Hero: Identifiable {
    var id = UUID()
    var name: String
    var superpower: SuperPower
    var isInHellMode: Bool
    
    static var previewHeros: [Hero] = {
       [
        Hero(name: "孙悟空", superpower: .immortal, isInHellMode: false),
        Hero(name: "钢铁侠", superpower: .immortal, isInHellMode: false),
        Hero(name: "闪电侠", superpower: .teleportation, isInHellMode: false),
        Hero(name: "吉良吉影", superpower: .predictTheFuture, isInHellMode: false),
        Hero(name: "灭霸", superpower: .timeStop, isInHellMode: true)
       ]
    }()
}

struct HerosView: View {
    
    @Binding var heroList: [Hero]
    
    var body: some View {
        NavigationStack {
            List($heroList) { $hero in
                VStack(alignment: .leading) {
                    HStack {
                        TextField("英雄名字", text: $hero.name)
                            .font(.title.weight(.black))
                        
                        Toggle("地狱模式", isOn: $hero.isInHellMode)
                            
                    }
                    
                    HStack {
                        Text(hero.superpower.description)
                            .font(.headline)
                            .foregroundStyle(.gray)
                        
                        Spacer()
                        
                        Text(hero.id.uuidString.suffix(8))
                            .font(.title2.weight(.heavy))
                            .foregroundStyle(.purple)
                            
                    }
                }
            }
            .navigationTitle("英雄列表")
            .toolbar {
                Text("大熊猫侯佩 @ \(Text("CSDN").foregroundStyle(.red))")
                    .font(.headline.weight(.bold))
                    .foregroundStyle(.gray)
            }
        }
    }
}

如上代码所示:我们希望在 Xcode 预览中调试的 HerosView 视图会被要求传入一个可变 heroList 状态,它的类型是 [Hero]。

在 SwiftUI 6.0(Xcode 16)之前,要想预览与 HerosView 翩翩起舞我们可能需要大费周章地另外写一个包装器视图,在该视图中创建一个 [Hero] 类型的状态,然后再把它传递给 HerosView。


除了用包装器的方式调试 HerosView 视图以外,我们还可以使用 #Preview + @Observable 宏的组合构造可变 @Binding 实参来向 HerosView 传递状态 。

更多细节请小伙伴们移步如下链接观赏进一步精彩的内容:


而现在 WWDC24 为我们送来了全新的 @Previewable 宏专注于解决此事:

有了 @Previewable 宏,我们即可怡然自得的在 #Preview 宏预览闭包中直接向被调试的 SwiftUI 视图传入可变状态了:

swift 复制代码
#Preview("英雄列表") {
    @Previewable @State var heros = Hero.previewHeros
    HerosView(heroList: $heros)
}

现在,我们在 Xcode 16 中可以易如反掌的调试需要传入可变状态的 SwiftUI 子视图了,棒棒哒💯:

总结

在本篇博文中,我们介绍了如何在最新的 SwiftUI 6.0(Xcode 16)中利用 WWDC24 中新祭出的 @Entry 和 @Previewable 宏让环境变量定义和 Xcode 界面预览调试更加得心应手,充满乐趣!

感谢观赏,再会!😎

相关推荐
大熊猫侯佩6 天前
Swift 宏(Macro)入门趣谈(二)
swift··macro·freestanding·attached·独立宏·附属宏
大熊猫侯佩12 天前
WWDC24(Xcode 16)中全新的 Swift Testing 使用进阶
单元测试·xctest·xcode 16·wwdc 24·swift testing·初始化和清理·测试顺序
大熊猫侯佩13 天前
用接地气的例子趣谈 WWDC 24 全新的 Swift Testing 入门(三)
单元测试·xcode 16·wwdc 24·swift 宏·swift testing·#expect·#require
dialog20 天前
excel的宏1
excel·
TYYJ-洪伟24 天前
Rust 程序设计语言学习——高级特性
rust··指针·函数指针·闭包·不安全
大熊猫侯佩1 个月前
SwiftUI 6.0(iOS 18)新增的网格渐变色 MeshGradient 解惑
动画·颜色·ios 18·swiftui 6.0·渐变色·gradient·网格渐变色
大熊猫侯佩1 个月前
SwiftUI 6.0(iOS 18)自定义容器值(Container Values)让容器布局渐入佳境(上)
foreach·group·layout·ios 18·swiftui 6.0·containervalues·自定义容器
Se7en丶潇洒哥2 个月前
Xcode 16 上传AppStore遇到第三方库 bitcode 的问题
ios·xcode·appstore·xcode 16·bitcode
小米里的大麦2 个月前
【C++】内联函数(inline function)详解
c++·笔记··inline·内联函数
Trouvaille ~3 个月前
【C语言篇】编译和链接以及预处理介绍(上篇)
c语言·缓存·预处理··编译和链接·翻译环境·运行环境