Token导航 LogoToken导航

Agent Skill · 研究检索

swiftdata(swiftdata 控制)

用于辅助数据整理、表格处理、CSV/Excel 分析、指标计算和图表准备。它适合让 Agent 清洗字段、汇总数据、发现异常、生成统计口径或把分析结果转成可读说明。使用时需要确认数据来源、字段含义和时间范围,避免把样本数据当全量事实;涉及敏感数据、导出文件或批量写回时,应先确认权限和脱敏边界。

swiftdata 是研究检索类 Agent Skill,可用宿主为 Codex、Claude、Cursor、Gemini CLI,通过GitHub 仓库获取,权限为需要联网;许可证信息还不明确,第三方扫描已通过,按安装量在研究检索类的 73,675 个 Skill 里排第 5,030。

总安装 28,224周安装 1,213GitHub Stars 469下载 9,888核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
unknown

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:swiftdata(swiftdata 控制)
来源仓库:https://github.com/dpearson2699/swift-ios-skills
仓库路径:skills/swiftdata
安装命令:
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swiftdata
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swiftdata

这个 Skill 是做什么的

研究检索类 Skill 主要解决「找资料、核对事实、把来源整理清楚」的问题,通常会让助手先检索再总结。

使用 SwiftData 和 Swift 6.2 在 iOS 26+ 应用程序中定义、保留和查询结构化数据。

使用@Model定义模型 类,@Attribute ,@关系 ,@瞬态 ,@独特 和@Index 装饰器;支持的类型包括基元、日期, 数据, 网址, UUID, 可编码 枚举/结构和关系 通过 ModelContext 进行 CRUD 操作 与@Query 对于反应式 SwiftUI 视图,#Predicate 用于类型安全过滤和 FetchDescriptor 用于带有排序、限制和预取的高级查询 使用 VersionedSchema 进行架构版本控制和迁移 和架构迁移计划 用于轻量级或自定义数据转换 通过 @ModelActor 的并发支持 用于后台工作;传递持久标识符 跨越参与者边界,从不直接对对象进行建模 CloudKit通过ModelConfiguration同步配置 以及核心数据的共存或迁移路径

来源仓库内路径:skills/swiftdata

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 Codex、Claude、Cursor、Gemini CLI;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swiftdat…;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要需要联网,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

swiftdata 怎么安装?

在终端执行 npx skills add https://github.com/dpearson2699/swift-ios-skills --skill swiftdata。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

swiftdata 支持哪些 AI 工具?

公开资料标注支持 Codex、Claude、Cursor、Gemini CLI。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

swiftdata 需要什么权限?

权限级别是需要联网。该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

swiftdata 是免费的吗?

公开资料没有标注明确许可证,收费和商用限制都无法确认。正式使用前请到来源仓库核对授权说明。

swiftdata 用的人多吗?

公开数据是累计安装 28,224 次,近一周安装 1,213 次,下载 9,888 次,GitHub 469 星。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

swiftdata 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 同时适配 4 种工具,换客户端不用重新找替代品。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 许可证没有明确标注,能不能商用、能不能再分发都不确定。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 Codex,想直接扩展它能力的人。
  • 需要处理研究检索类任务、又不想每次都手写提示词的人。

不太适合

  • 需要明确授权才能用到公司项目里的场景。
  • 需要厂商级技术支持和 SLA 的生产系统。

研究检索类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
find-skills

寻找技能 · Codex、Claude

31,199,81316,486操作浏览器MIT有提醒
self-improving-agent

自我改进 Agent · OpenClaw

16,464,0023,396接触敏感数据MIT-0通过
soultrace

灵魂追踪 · Codex、Claude

7,588,94412需要联网未明确有提醒
self-improving

自我完善 · OpenClaw

6,829,2841,046需要联网MIT-0通过
microsoft-foundry

微软代工厂 · Codex、Claude

6,614,144764调用外部服务未明确有提醒
swiftdata

swiftdata 控制 · 本页

28,224469需要联网未明确通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

SwiftData

Persist, query, and manage structured data in iOS 26+ apps using SwiftData with Swift 6.3.

Contents

Model Definition

Apply @Model to a class (not struct). Generates PersistentModel, Observable, Sendable.

@Model
class Trip {
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date
    var isFavorite: Bool = false
    @Attribute(.externalStorage) var imageData: Data?
    @Relationship(deleteRule: .cascade, inverse: \LivingAccommodation.trip)
    var accommodation: LivingAccommodation?
    @Transient var isSelected: Bool = false  // Always provide default

    init(name: String, destination: String, startDate: Date, endDate: Date) {
        self.name = name; self.destination = destination
        self.startDate = startDate; self.endDate = endDate
    }
}

@Attribute options: .externalStorage, .unique, .spotlight, .allowsCloudEncryption, .preserveValueOnDeletion (iOS 18+), .ephemeral, .transformable(by:). Rename: @Attribute(originalName: "old_name").

@Relationship: deleteRule: .cascade/.nullify(default)/.deny/.noAction. Specify inverse: for reliable behavior. Unidirectional (iOS 18+): inverse: nil.

#Unique (iOS 18+): #Unique<Person>([\.firstName, \.lastName]) -- compound uniqueness.

Inheritance (iOS 26+): @Model class BusinessTrip: Trip {var company: String}.

Supported types: Bool, Int/UInt variants, Float, Double, String, Date, Data, URL, UUID, Decimal, Array, Dictionary, Set, Codable enums, Codable structs (composite, iOS 18+), relationships to @Model classes.

ModelContainer Setup

// Basic
let container = try ModelContainer(for: Trip.self, LivingAccommodation.self)

// Configured
let config = ModelConfiguration("Store", isStoredInMemoryOnly: false,
    groupContainer: .identifier("group.com.example.app"),
    cloudKitDatabase: .private("iCloud.com.example.app"))
let container = try ModelContainer(for: Trip.self, configurations: config)

// With migration plan
let container = try ModelContainer(for: SchemaV2.Trip.self,
    migrationPlan: TripMigrationPlan.self)

// In-memory (previews/tests)
let container = try ModelContainer(for: Trip.self,
    configurations: ModelConfiguration(isStoredInMemoryOnly: true))

CRUD Operations

// CREATE
let trip = Trip(name: "Summer", destination: "Paris", startDate: .now, endDate: .now + 86400*7)
modelContext.insert(trip)
try modelContext.save()  // or rely on autosave

// READ
let trips = try modelContext.fetch(FetchDescriptor<Trip>(
    predicate: #Predicate { $0.destination == "Paris" },
    sortBy: [SortDescriptor(\.startDate)]))

// UPDATE -- modify properties directly; autosave handles persistence
trip.destination = "Rome"

// DELETE
modelContext.delete(trip)
try modelContext.delete(model: Trip.self, where: #Predicate { $0.isFavorite == false })

// TRANSACTION (atomic)
try modelContext.transaction {
    modelContext.insert(trip); trip.isFavorite = true
}

@Query in SwiftUI

struct TripListView: View {
    @Query(filter: #Predicate<Trip> { $0.isFavorite == true },
           sort: \.startDate, order: .reverse)
    private var favorites: [Trip]

    var body: some View { List(favorites) { trip in Text(trip.name) } }
}

// Dynamic query via init
struct SearchView: View {
    @Query private var trips: [Trip]
    init(search: String) {
        _trips = Query(filter: #Predicate<Trip> { trip in
            search.isEmpty || trip.name.localizedStandardContains(search)
        }, sort: [SortDescriptor(\.name)])
    }
    var body: some View { List(trips) { trip in Text(trip.name) } }
}

// FetchDescriptor query
struct RecentView: View {
    static var desc: FetchDescriptor<Trip> {
        var d = FetchDescriptor<Trip>(sortBy: [SortDescriptor(\.startDate)])
        d.fetchLimit = 5; return d
    }
    @Query(RecentView.desc) private var recent: [Trip]
    var body: some View { List(recent) { trip in Text(trip.name) } }
}

#Predicate

#Predicate<Trip> { $0.destination.localizedStandardContains("paris") }  // String
#Predicate<Trip> { $0.startDate > Date.now }                            // Date
#Predicate<Trip> { $0.isFavorite && $0.destination != "Unknown" }       // Compound
#Predicate<Trip> { $0.accommodation?.name != nil }                      // Optional
#Predicate<Trip> { $0.tags.contains { $0.name == "adventure" } }        // Collection

Supported: ==, !=, <, <=, >, >=, &&, ||, !, contains(), allSatisfy(), filter(), starts(with:), localizedStandardContains(), caseInsensitiveCompare(), arithmetic, ternary, optional chaining, nil coalescing, type casting. Not supported: flow control, nested declarations, arbitrary method calls.

FetchDescriptor

var d = FetchDescriptor<Trip>(predicate: ..., sortBy: [...])
d.fetchLimit = 20; d.fetchOffset = 0
d.includePendingChanges = true
d.propertiesToFetch = [\.name, \.startDate]
d.relationshipKeyPathsForPrefetching = [\.accommodation]
let trips = try modelContext.fetch(d)
let count = try modelContext.fetchCount(d)
let ids = try modelContext.fetchIdentifiers(d)
try modelContext.enumerate(d, batchSize: 1000) { trip in trip.isProcessed = true }

Schema Versioning and Migration

enum SchemaV1: VersionedSchema {
    static var versionIdentifier = Schema.Version(1, 0, 0)
    static var models: [any PersistentModel.Type] { [Trip.self] }
    @Model class Trip { var name: String; init(name: String) { self.name = name } }
}

enum SchemaV2: VersionedSchema {
    static var versionIdentifier = Schema.Version(2, 0, 0)
    static var models: [any PersistentModel.Type] { [Trip.self] }
    @Model class Trip {
        var name: String; var startDate: Date?  // New property
        init(name: String) { self.name = name }
    }
}

enum TripMigrationPlan: SchemaMigrationPlan {
    static var schemas: [any VersionedSchema.Type] { [SchemaV1.self, SchemaV2.self] }
    static var stages: [MigrationStage] { [migrateV1toV2] }
    static let migrateV1toV2 = MigrationStage.lightweight(
        fromVersion: SchemaV1.self, toVersion: SchemaV2.self)
}

// Custom migration for data transformation
static let migrateV2toV3 = MigrationStage.custom(
    fromVersion: SchemaV2.self, toVersion: SchemaV3.self,
    willMigrate: nil,
    didMigrate: { context in
        let trips = try context.fetch(FetchDescriptor<SchemaV3.Trip>())
        for trip in trips { trip.displayName = trip.name.capitalized }
        try context.save()
    })

Lightweight handles: adding optional/defaulted properties, renaming (originalName), removing properties, adding model types.

Concurrency (@ModelActor)

@ModelActor
actor DataHandler {
    func importTrips(_ records: [TripRecord]) throws {
        for r in records {
            modelContext.insert(Trip(name: r.name, destination: r.dest,
                                    startDate: r.start, endDate: r.end))
        }
        try modelContext.save()  // Always save explicitly in @ModelActor
    }

    func process(tripID: PersistentIdentifier) throws {
        guard let trip = self[tripID, as: Trip.self] else { return }
        trip.isProcessed = true; try modelContext.save()
    }
}

let handler = DataHandler(modelContainer: container)
try await handler.importTrips(records)

Rules: ModelContainer is Sendable. ModelContext is NOT -- use on its creating actor. Pass PersistentIdentifier (Sendable) across boundaries. Never pass @Model objects across actors.

SwiftUI Integration

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }
            .modelContainer(for: [Trip.self, LivingAccommodation.self])
    }
}

struct DetailView: View {
    @Environment(\.modelContext) private var modelContext
    let trip: Trip
    var body: some View {
        Text(trip.name)
        Button("Delete") { modelContext.delete(trip) }
    }
}

#Preview {
    let config = ModelConfiguration(isStoredInMemoryOnly: true)
    let container = try! ModelContainer(for: Trip.self, configurations: config)
    container.mainContext.insert(Trip(name: "Preview", destination: "London",
        startDate: .now, endDate: .now + 86400))
    return TripListView().modelContainer(container)
}

Common Mistakes

1. @Model on struct -- Use class. @Model requires reference semantics.

2. @Transient without default -- Always provide default: @Transient var x: Bool = false.

3. Missing.modelContainer -- @Query returns empty without a container on the view hierarchy.

4. Passing model objects across actors:

// WRONG: await handler.process(trip: trip)
// CORRECT: await handler.process(tripID: trip.persistentModelID)

5. ModelContext on wrong actor:

// WRONG: Task.detached { context.fetch(...) }
// CORRECT: Use @ModelActor for background work

6. Unsupported #Predicate expressions:

// WRONG: #Predicate<Trip> { $0.name.uppercased() == "PARIS" }
// CORRECT: #Predicate<Trip> { $0.name.localizedStandardContains("paris") }

7. Flow control in #Predicate:

// WRONG: #Predicate<Trip> { for tag in $0.tags { ... } }
// CORRECT: #Predicate<Trip> { $0.tags.contains { $0.name == "x" } }

8. No save in @ModelActor -- Always call try modelContext.save() explicitly.

9. ObservableObject with @Model -- Never use ObservableObject/@Published. @Model generates Observable. Use @Query in views.

10. Non-optional relationship without default:

// WRONG: var accommodation: LivingAccommodation  // crashes on reconstitution
// CORRECT: var accommodation: LivingAccommodation?

11. Cascade without inverse -- Specify inverse: for reliable cascade delete behavior.

12. DispatchQueue for background data work:

// WRONG: DispatchQueue.global().async { ModelContext(container).fetch(...) }
// CORRECT: @ModelActor actor Handler { func fetch() throws { ... } }

Review Checklist

  • Every @Model is a class with a designated initializer
  • All @Transient properties have default values
  • Relationships specify deleteRule and inverse
  • .modelContainer attached at scene/root view level
  • @Query used for reactive data display in SwiftUI
  • #Predicate uses only supported operators
  • Background work uses @ModelActor
  • PersistentIdentifier used across actor boundaries
  • Schema changes have VersionedSchema + SchemaMigrationPlan
  • Large data uses @Attribute(.externalStorage)
  • CloudKit models use optionals and avoid unique constraints
  • Explicit save() in @ModelActor methods
  • Previews use ModelConfiguration(isStoredInMemoryOnly: true)
  • @Model classes accessed from SwiftUI views are on @MainActor via @ModelActor or MainActor isolation

References

平台分布

Codex

35.86%
按下载量换算3,546

Claude

32.35%
按下载量换算3,199

Cursor

19.39%
按下载量换算1,917

Gemini CLI

9.56%
按下载量换算945

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills