iOS 18 中全新 SwiftData 重装升级,其中一个功能保证你们“爱不释手”

在这里插入图片描述

概览

在最新的 WWDC 2024 中,苹果对多个系统框架都做了重量级的功能升级。这怎么能够少了 SwiftData 这位“后起之秀”呢?

在这里插入图片描述

万象更新的 iOS 18 为 SwiftData 增加了全新的唯一性、自定义数据仓库、富表达式以及字段索引等超赞功能。

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

  • 概览
  • 1. 什么是 SwiftData?
  • 2. 新的 #Unique 宏
  • 3. 历史数据操作记录
  • 4. 自定义数据仓库(Data Stores)
  • 5. Xcode 预览 Traits
  • 6. 自定义额外数据 Queries
  • 7. #Expression 表达式宏
  • 8. #Index 宏
  • 总结

闲言少叙,让我们马上一起跃入 SwiftData 焕然一新的世界中吧!

Let‘s go!!!😉


1. 什么是 SwiftData?

在去年苹果乘着 iOS 17 的东风祭出了全新纯 Swifty 范儿的数据库 SwiftData。

在这里插入图片描述

利用 SwiftData 我们仅用寥寥几行描述性代码就可以易如反掌的构建出一个“羽翼丰满”的数据库支持应用。

SwiftData 内置了海量的功能特性,我们可以用它们来搭建本地或者 iCloud 支持的复杂数据库 App。
在这里插入图片描述

如下代码所示,我们借助 @Model 宏将平淡无奇的 Trip、BucketListItem 以及 LivingAccommodation 类转换为了持久存储背后“撑腰”的 SwiftData 类型:

// Trip Models decorated with @Model
import Foundation
import SwiftData

@Model
class Trip {
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    
    var bucketList: [BucketListItem] = [BucketListItem]()
    var livingAccommodation: LivingAccommodation?
}

@Model
class BucketListItem {...}

@Model
class LivingAccommodation {...}

有了上面的类型定义,我们就可以自然而然的将数据融入到 SwiftUI 视图中啦:

// Trip App using modelContainer Scene modifier
import SwiftUI
import SwiftData

@main
struct TripsApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView
        }
        .modelContainer(for: Trip.self)
    }
}

除此之外,借助于 Swift 5.9 中新的宏(Macro)机制我们可以恣意设置和调整 SwiftData 类型中各个属性和关系。比如,我们可以使用 @Transient 修饰符让类中对应的属性不占据数据库的字段空间而是仅存于内存中。

在这里插入图片描述

2. 新的 #Unique 宏

从 iOS 18 开始,苹果为 SwiftData 增加了新的 #Unique 宏用来表示类型中属性的唯一性,并且当新插入的对象与已有对象发生冲突时(Collisions)将新增操作改为数据更新操作:

在这里插入图片描述

在下面的代码中,我们利用 #Unique 宏将 Trip 类中 name、startDate 和 endDate 三个属性的值组合为判断 Trip 在数据库中存在唯一性的判断标准:

// Add unique constraints to avoid duplication
import SwiftData

@Model 
class Trip {
    #Unique<Trip>([\.name, \.startDate, \.endDate])
    
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    
    var bucketList: [BucketListItem] = [BucketListItem]()
    var livingAccommodation: LivingAccommodation?
}

这样一来,借助 #Unique 宏我们即可省去大量附加判断代码,在数据库层面完成托管对象唯一性的检查。

3. 历史数据操作记录

有了上面的 #Unique 宏,我们还可以进一步为 SwiftData 类型的实例属性添加历史(History)记录支持。

在这里插入图片描述

如下代码所示,我们利用 @Attribute 宏在 #Unique 对应的三个属性上开启了 .preserveValueOnDeletion 特性:

// Add .preserveValueOnDeletion to capture unique columns
import SwiftData

@Model 
class Trip {
    #Unique<Trip>([\.name, \.startDate, \.endDate])
    
    @Attribute(.preserveValueOnDeletion)
    var name: String
    var destination: String

    @Attribute(.preserveValueOnDeletion)
    var startDate: Date

    @Attribute(.preserveValueOnDeletion)
    var endDate: Date
    
    var bucketList: [BucketListItem] = [BucketListItem]()
    var livingAccommodation: LivingAccommodation?
}

这样一来我们就将上面三个属性变为了墓碑(tombstone)属性,使他们可以在 Trip 托管对象被删除时在历史记录中得以显现,以便让用户可以直观查看到数据库的“变迁史”。

4. 自定义数据仓库(Data Stores)

在之前的 SwiftData 中我们可以在 SwiftUI 里用 .modelContainer 修改器为特定托管类型创建对应的模型容器:

// Trip App using modelContainer Scene modifier
import SwiftUI
import SwiftData

@main
struct TripsApp: App {   
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: Trip.self)
   }
}

我们也可以根据需求创建“心有所想”的复杂模型容器,比如在下面代码中我们创建的 Model Container 容器让所有 Trip 托管对象仅存活于内存中、并开启了自动保存和 Undo 功能:

// Customize a model container in the app
import SwiftUI
import SwiftData

@main
struct TripsApp: App {   
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: Trip.self,
                        inMemory: true,
                        isAutosaveEnabled: true,
                        isUndoEnabled: true)
   }
}

不仅如此,我们还有更加无拘无束创建模型容器的自由:

// Add a model container to the app
import SwiftUI
import SwiftData

@main
struct TripsApp: App {
    var container: ModelContainer = {
        do {
            let configuration = ModelConfiguration(schema: Schema([Trip.self]), url: fileURL)
            return try ModelContainer(for: Trip.self, configurations: configuration)
        }
        catch { ... }
    }()
    
   var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
   }
}

好消息来了!从 iOS 18 开始我们可以更进一步创建自定义数据仓库 Data Stores,这样数据仓库会拥有更加健壮、更加自由的持久后端支持。这是第一次我们可以在 SwiftData 中创建自己的数据存储仓库:

// Use your own custom data store
import SwiftUI
import SwiftData

@main
struct TripsApp: App {
    var container: ModelContainer = {
        do {
            let configuration = JSONStoreConfiguration(schema: Schema([Trip.self]), url: jsonFileURL)
            return try ModelContainer(for: Trip.self, configurations: configuration)
        }
        catch { ... }
    }()
    
   var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(container)
   }
}

想要了解 Data Stores 定制的更多内容,大家可以进一步观赏下图中的 WWDC24 视频课:

在这里插入图片描述

5. Xcode 预览 Traits

大家知道,SwiftData 与 SwiftUI 搭配可谓是“双剑合璧天下无敌”,而 Xcode 预览(Preview)又对 SwiftUI 界面调试有着“匪夷所思”的优秀支持。

在这里插入图片描述

在 iOS 18 中,我们可以让 SwiftData 数据模型在 Xcode 的预览中继续大放异彩。这可以通过预览的 Trait 机制来完成:

// Make preview data using traits

struct SampleData: PreviewModifier {
    static func makeSharedContext() throws -> ModelContainer {
        let config = ModelConfiguration(isStoredInMemoryOnly: true)
        let container = try ModelContainer(for: Trip.self, configurations: config)
        Trip.makeSampleTrips(in: container)
        return container
    }
    
    func body(content: Content, context: ModelContainer) -> some View {
        content.modelContainer(context)
    }
}

extension PreviewTrait where T == Preview.ViewTraits {
    @MainActor static var sampleData: Self = .modifier(SampleData())
}

在上面的代码中,我们让 SampleData 遵循 PreviewModifier 协议并知趣的实现其中两个方法。

这样一来,在 Xcode 预览中使用 SampleData 提供的 SwiftData 数据源就变成“探囊取物”一般的简单啦:

// Use sample data in a preview

import SwiftUI
import SwiftData

struct ContentView: View {
    @Query
    var trips: [Trip]

    var body: some View {
        ...
    }
}

#Preview(traits: .sampleData) {
    ContentView()
}

6. 自定义额外数据 Queries

在 Xcode 预览的调试中,对于某些视图来说其本身并不包含 Query 属性而是需要从外部传入它们。

在这里插入图片描述

从 iOS 18 开始,SwiftData 也为其提供了更“银杏化”的支持。现在我们可以直接在预览 #Preview 附着的闭包中插入所需的 Query 状态了,这是通过 @Previewable 宏来实现的:

// Create a preview query using @Previewable

import SwiftUI
import SwiftData

#Preview(traits: .sampleData) {
    @Previewable @Query var trips: [Trip]
    BucketListItemView(trip: trips.first)
}

有了新的 @Previewable 宏,为特定视图创建 Query 数据集变得史无前例的简单了。

7. #Expression 表达式宏

从 iOS 17 开始,苹果推出了新的 #Predicate 宏让我们可以自由自在的构建数据查询相关的断言(Predicate):

// Create a Predicate to find a Trip based on Search Text

let predicate = #Predicate<Trip> {
    searchText.isEmpty ? true : $0.name.localizedStandardContains(searchText)
}

除了简单的条件以外,我们还可以在 #Predicate 闭包中合成复杂的多条件查询语句:

// Create a Compound Predicate to find a Trip based on Search Text

let predicate = #Predicate<Trip> {
    searchText.isEmpty ? true :
    $0.name.localizedStandardContains(searchText) ||
    $0.destination.localizedStandardContains(searchText)
}

在这里插入图片描述

如今,在 iOS 18+ 中我们的自由度进一步得到与时俱进的增强。现在我们可以使用全新的 #Expression 宏来让断言的表达能力更加“突飞猛进”:

// Build a predicate to find Trips with BucketListItems that are not in the plan

let unplannedItemsExpression = #Expression<[BucketListItem], Int> { items in
    items.filter {
        !$0.isInPlan
    }.count
}

let today = Date.now
let tripsWithUnplannedItems = #Predicate<Trip>{ trip
    // The current date falls within the trip
    (trip.startDate ..< trip.endDate).contains(today) &&

    // The trip has at least one BucketListItem
    // where 'isInPlan' is false
    unplannedItemsExpression.evaluate(trip.bucketList) > 0
}

如上代码所示:我们利用新的 #Expression 宏创建了 unplannedItemsExpression 表达式,并将其应用在了 tripsWithUnplannedItems 断言中从而创建出有史以来最复杂、最富表现力的复合查询条件。

8. #Index 宏

大家都知道,在数据库的查询等操作中为特定字段增加索引可以极大的增加查表速度。

从 iOS 18 开始,数据库索引机制终于显式加入到了 SwiftData 中,这是通过 #Index 宏实现的。

在这里插入图片描述


关于 Apple 数据库相关索引机制的进一步介绍,感兴趣的小伙伴们可以移步如下链接继续观赏精彩的内容:

  • SwiftUI 后台刷新多个 Section 导致 global index in collection view 与实际不匹配问题的解决
  • 探究 CoreData 使用索引(Index)机制加速查表究竟如何实现?

这是一个令我们喜不自胜的 SwiftData 新功能!

使用全新的 #Index 宏我们可以为数据类型中经常访问的特定属性增加查表索引,以便增加查询效率。

如下代码所示,我们不仅可以在单个属性上增加索引,还可以将索引应用到多个属性组合上去。

// Add Index for commonly used KeyPaths or combination of KeyPaths
import SwiftData

@Model 
class Trip {
    #Unique<Trip>([\.name, \.startDate, \.endDate
    #Index<Trip>([\.name], [\.startDate], [\.endDate], [\.name, \.startDate, \.endDate])

    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    
    var bucketList: [BucketListItem] = [BucketListItem
    var livingAccommodation: LivingAccommodation
}

为托管类型增加索引,不仅有利于查表速度,对于海量数据的筛选和排序也会大有裨益,棒棒哒!💯

总结

在本篇博文中,我们介绍了 iOS 18 中 SwiftData 框架的“重装升级”。其中我感觉 #Expression 和 #Index 宏对小伙伴的实际帮助更为突出,大家怎么认为呢?欢迎讨论哦。

在这里插入图片描述

感谢观赏,再会!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/710846.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

植物大战僵尸杂交版 v2.0.88 mac版 Plants vs. Zombies 杂交版下载

特别注意&#xff1a;该游戏最低系统要求为macOS Sonoma 14.X&#xff0c;低于此系统版本的请勿下载&#xff01; 游戏介绍 植物大战僵尸杂交版是由B站UP主“潜艇伟伟迷”制作的一款结合了《植物大战僵尸》原有元素与创新玩法的游戏。这款游戏以其独特的“杂交”植物概念在B站…

提醒:网站使用微软雅黑字体的三种方式,两种侵权,一种不侵权。

大家都知道微软雅黑是windows系统的默认字体&#xff0c;但是不知道微软雅黑的版权归属方正字体&#xff0c;而且方正字体仅仅授权了微软在windows系统中使用该字体&#xff0c;脱离了windows使用&#xff0c;那是极易中招的&#xff0c;网页字体使用是前端开发的工作之一&…

H5拟态个人主页

文末有该项目的源码~ 这张图片的效果你是不是非常想要get同款&#xff1f; 源码就是这个样子 这段HTML代码构建了一个个人主页&#xff0c;结合了CSS样式和JavaScript功能。 下面是对代码的主要组成部分的详细解释&#xff1a; 基本结构 <!DOCTYPE html> 定义文档类型…

进来学习Kubernetes知识点

Kubernetes集群部署 文章目录 Kubernetes集群部署一、Kubernetes概述1.1、什么是Kubernetes1.2、为什么要用Kubernetes 二、Kubernetes组件2.1、Master组件2.2、Node组件 三、Kubernetes资源对象3.1、Pod3.2、Label3.3、Replication Controller3.4、Deployment3.5、Service3.6、…

数据库第一次实验报告

1. 使用 SQL 语句创建数据库 studentsdb。 2. 使用 SQL 语句选择 studentsdb 为当前使用数据库。 3. 使用 SQL 语句在 studentsdb 数据库创建数据表 student_info、curriculum、grade 4. 使用 SQL 语句 INSERT 向 studentsdb 数据库的 student_info、curriculum、grade 表插…

异常封装类统一后端响应的数据格式

异常封装类 如何统一后端响应的数据格式 1. 背景 后端作为数据的处理和响应&#xff0c;如何才能和前端配合好&#xff0c;能够高效的完成任务&#xff0c;其中一个比较重要的点就是后端返回的数据格式。 没有统一的响应格式&#xff1a; // 第一种&#xff1a; {"dat…

java:自定义注解,并使用【ImportBeanDefinitionRegistrar】动态加载

# 项目代码资源&#xff1a; 可能还在审核中&#xff0c;请等等。。。 https://download.csdn.net/download/chenhz2284/89432848 # 主项目 【pom.xml】 <groupId>com.chz</groupId> <artifactId>chzopen_study</artifactId> <packaging>pom…

嵌入式操作系统_4.任务管理

1.任务的概念 任务管理是嵌入式操作系统最基本功能之一&#xff0c;这里的任务&#xff08;task&#xff09;是指嵌入式操作系统调度的最小单位&#xff0c;类似于一般操作系统进程或线程的概念。任务是运行中的一个程序&#xff0c;一个程序加载到内存后就变成任务&#xff1…

InnoDB和MyISAM有什么区别?

InnoDB和MyISAM是MySQL中比较常用的两个执行引擎&#xff0c;MySQL在 5.5 之前版本默认存储引擎是 MyISAM,5.5 之后版本默认存储引擎是 InnoDB&#xff0c;MYISAM适合查询以及插入为主的应用&#xff0c;InnoDB适合频繁修改以及涉及到安全性较高的应用。 如果应用需要高度的数…

如果给电商系统颜值搞排名,我觉得淘宝千牛系统是天花板了。

淘宝的商家操作界面-千牛系统经过多年的迭代&#xff0c;无论从颜值上、功能上还是用户体验上都是行业天花板的存在&#xff0c;我截图软件上的一些图给大家分享下。

AirPlay技术规范及认证资讯

AirPlay是Apple开发的一种无线技术&#xff0c;允许用户将音频、视频或图片从iOS设备、Mac电脑或其他支持AirPlay的设备无线传输到支持AirPlay的接收器设备上&#xff0c;例如智能电视或音响系统。这项技术基于Wi-Fi网络&#xff0c;提供了一种便捷的方式来共享媒体内容。AirPl…

模型 POA行动

说明&#xff1a;系列文章 分享 模型&#xff0c;了解更多&#x1f449; 模型_思维模型目录。让目标凝聚伙伴&#xff0c;伙伴共创方法&#xff0c;加速实现愿景&#xff0c;可谓是行动力的“飞轮效应”。 1 POA行动模型的应用 1.1 POA模型在非营利组织&#xff08;NGO&#x…

算法day31

第一题 542. 01 矩阵 本题本来求解的是每一个1到0的最短距离并返回到矩阵之中&#xff1b; 我们采用正难则反的思路&#xff0c;将其化解为每一个0到每一个1的最短距离&#xff0c;并通过矩阵来返回&#xff1b; 解法&#xff1a;多源bfs正难则反 步骤一&#xff1a; 定义一个…

PDF标准详解(三)—— PDF坐标系统和坐标变换

之前我们了解了PDF文档的基本结构&#xff0c;并且展示了一个简单的hello world。这个hello world 虽然只在页面中显示一个hello world 文字&#xff0c;但是包含的内容却是不少。这次我们仍然以它为切入点&#xff0c;来了解PDF的坐标系统以及坐标变换的相关知识 图形学中二维…

利用Cesium和JS实现地点点聚合功能

引言 在实现基于地图的业务场景时&#xff0c;当地图上需要展示过多的标记点时&#xff0c;大量的分散点会使地图上显得杂乱无章&#xff0c;导致标记点对地图上的其他重要信息造成遮挡和混淆&#xff0c;降低地图整体的可读性。 标记点的聚合就很好的解决了这些痛点的同时&a…

线性规划问题——单纯形算法

第一步&#xff1a;化“约束标准型” 在每个等式约束中至少有一个变量的系数为正&#xff0c;且这个变量只在该约束中出现。在每个约束方程中选择一个这样的变量称为基本变量。 剩下变量称为非基本变量。 一个简单的栗子 上图是一个约束标准型线性规划的例子。 等式1&#x…

几款让你怦然心动的神奇工具——搜嗖工具箱

alteredqualia AlteredQualia 脑洞爆炸器网站&#xff0c;不得不说这是一个神奇的网站&#xff0c;在这个网站上你可以实现不可思议的各种操作&#xff0c;让我们对网站有了新的认知&#xff0c;因为它告诉你不是所有有趣的网站都那么花哨&#xff0c;有些网站看着外形平淡无奇…

AI实践与学习5-AI解题场景RAG应用预研demo

背景 AI解题场景现状&#xff0c;教研测评文档&#xff1a;xxx 解题正确率仍需进一步提高&#xff0c;提示词优化方案基本无力o目前配置的易错题CoT示例支持的长度有限&#xff0c;后续题量大的时候配置具有局限性。某些英语翻译题型BAD CASE反映大模型的输出格式不太符合要求…

设置sqlserver management的字体大小

在用sqlserver management的时候&#xff0c;总感觉怪怪的&#xff0c;然后发现是字体太小的原因。 1&#xff09;设置一下字体&#xff0c;工具--选项&#xff1a; 2&#xff09;环境--字体和颜色--显示其设置&#xff08;环境&#xff09; 3&#xff09;选择微软雅黑&#xf…

在Kubernetes中部署Elasticsearch高可用集群详细教程

Hi~&#xff01;这里是奋斗的小羊&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f4a5;&#x1f4a5;个人主页&#xff1a;奋斗的小羊 &#x1f4a5;&#x1f4a5;所属专栏&#xff1a;C语言 &#x1f680;本系列文章为个人学习…