Token导航 LogoToken导航TokenDH.com
开发规范需要联网github未标认证来源可访问许可证需确认审计通过

swiftui-best-practicesSwiftUI 最佳实践

Agent Skill

swiftui-best-practices 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

306

周安装

13

GitHub Stars

4

下载量

107
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

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

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

命令行安装

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

skills.shnpx skills
npx skills add https://github.com/creeveliu/ios-skills --skill swiftui-best-practices

简介

swiftui-best-practices 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • 可结合来源仓库和原始 README 继续核验具体用法。

SKILL.md

SwiftUI 最佳实践

本技能提供 SwiftUI 开发的标准工作流程和最佳实践。

核心原则

  1. 单一数据源 - 状态管理清晰,数据流向明确
  2. 值类型语义 - 充分利用 struct 的值类型特性
  3. 声明式 UI - 视图是状态的函数
  4. 组合优于继承 - 通过组合构建可复用组件
  5. 性能优先 - 避免不必要的视图重建

状态管理

属性包装器选择指南

// @State - 视图私有状态
struct CounterView: View {
    @State private var count = 0  // ✅ 视图内部管理

    var body: some View {
        Button("Count: \(count)") {
            count += 1
        }
    }
}

// @Binding - 与父视图共享状态
struct StepperView: View {
    @Binding var value: Int  // ✅ 引用父视图的状态

    var body: some View {
        Stepper("Value: \(value)", value: $value)
    }
}

// Parent view
struct ParentView: View {
    @State private var stepperValue = 0

    var body: some View {
        StepperView(value: $stepperValue)  // 传递绑定
    }
}

// @StateObject - 拥有并创建可观察对象
class ViewModel: ObservableObject {
    @Published var data: String = ""
}

struct FormView: View {
    @StateObject private var viewModel = ViewModel()  // ✅ 视图创建并拥有

    var body: some View {
        TextField("Enter text", text: $viewModel.data)
    }
}

// @ObservedObject - 引用外部可观察对象
struct DetailView: View {
    @ObservedObject var viewModel: ViewModel  // ✅ 外部传入

    var body: some View {
        Text(viewModel.data)
    }
}

// @EnvironmentObject - 跨层级共享
struct ContentView: View {
    @EnvironmentObject var userSettings: UserSettings

    var body: some View {
        Text(userSettings.username)
    }
}

// 注册环境对象
ContentView()
    .environmentObject(UserSettings())

状态提升模式

// ✅ 正确:状态提升到共同父视图
struct ParentView: View {
    @State private var searchText = ""

    var body: some View {
        VStack {
            SearchField(text: $searchText)
            ResultsList(searchText: searchText)
        }
    }
}

struct SearchField: View {
    @Binding var text: String

    var body: some View {
        TextField("Search...", text: $text)
    }
}

struct ResultsList: View {
    let searchText: String

    var body: some View {
        List {
            Text("Results for: \(searchText)")
        }
    }
}

// ❌ 错误:状态分散在多个子视图

ObservableObject 最佳实践

// ✅ 正确:使用 @MainActor 确保线程安全
@MainActor
class ContentViewModel: ObservableObject {
    @Published private(set) var items: [Item] = []
    @Published var isLoading = false
    @Published var errorMessage: String?

    private let service: DataService

    init(service: DataService = .shared) {
        self.service = service
    }

    func loadItems() async {
        isLoading = true
        defer { isLoading = false }

        do {
            items = try await service.fetchItems()
            errorMessage = nil
        } catch {
            errorMessage = error.localizedDescription
        }
    }
}

// ✅ 正确:拆分大型 ViewModel
class UserViewModel: ObservableObject {
    @Published var profile: UserProfile
    @Published var settings: UserSettings
}

// 更好:使用多个小对象
struct UserProfile { }
struct UserSettings { }

视图架构

视图组件化

// ✅ 正确:提取可复用组件
struct UserProfileView: View {
    let user: User

    var body: some View {
        VStack(spacing: 16) {
            AvatarView(imageURL: user.avatarURL)
            NameView(name: user.name)
            BioView(bio: user.bio)
        }
    }
}

struct AvatarView: View {
    let imageURL: URL?

    var body: some View {
        AsyncImage(url: imageURL) { image in
            image.resizable()
                .aspectRatio(contentMode: .fill)
        } placeholder: {
            Image(systemName: "person.circle")
        }
        .frame(width: 80, height: 80)
        .clipShape(Circle())
    }
}

// ✅ 正确:使用 @ViewBuilder 创建复杂视图
struct CardView<Content: View>: View {
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            content
        }
        .padding()
        .background(Color(.systemBackground))
        .cornerRadius(12)
        .shadow(color: .black.opacity(0.1), radius: 4, x: 0, y: 2)
    }
}

条件视图

// ✅ 正确:使用 Group 或直接条件渲染
var body: some View {
    VStack {
        if isLoading {
            ProgressView()
        } else if items.isEmpty {
            EmptyStateView()
        } else {
            ContentView(items: items)
        }
    }
}

// ✅ 正确:使用 switch
var body: some View {
    switch state {
    case .loading:
        ProgressView()
    case .empty:
        EmptyStateView()
    case .content(let items):
        ContentView(items: items)
    }
}

// ❌ 错误:在 body 中执行复杂逻辑
var body: some View {
    {
        if condition {
            return SomeView()
        }
        return OtherView()
    }()
}

列表优化

// ✅ 正确:使用 id 参数帮助 SwiftUI 追踪变化
List(items, id: \.id) { item in
    ItemRow(item: item)
}

// ✅ 正确:使用 ForEach 处理静态列表
ForEach(categories) { category in
    CategoryRow(category: category)
}

// ✅ 正确:删除动画
List {
    ForEach(items) { item in
        ItemRow(item: item)
            .swipeActions {
                Button("Delete", role: .destructive) {
                    withAnimation {
                        items.removeAll { $0.id == item.id }
                    }
                }
            }
}

互操作性

UIKit 集成

// ✅ 正确:使用 UIViewRepresentable 封装 UIKit
struct WebView: UIViewRepresentable {
    let url: URL

    func makeUIView(context: Context) -> WKWebView {
        let webView = WKWebView()
        webView.delegate = context.coordinator
        return webView
    }

    func updateUIView(_ webView: WKWebView, context: Context) {
        let request = URLRequest(url: url)
        webView.load(request)
    }

    func makeCoordinator() -> Coordinator {
        Coordinator()
    }

    class Coordinator: NSObject, WKNavigationDelegate {
        func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
            // 处理完成
        }
    }
}

// ✅ 正确:使用 UIViewControllerRepresentable
struct SheetView: UIViewControllerRepresentable {
    let onDismiss: () -> Void

    func makeUIViewController(context: Context) -> UINavigationController {
        let viewController = ContentViewController()
        viewController.onDismiss = onDismiss
        return UINavigationController(rootViewController: viewController)
    }

    func updateUIViewController(_ controller: UINavigationController, context: Context) {
        // 更新逻辑
    }
}

双向绑定

// ✅ 正确:UIKit 组件的双向绑定
struct TextFieldWrapper: UIViewRepresentable {
    @Binding var text: String
    var placeholder: String

    func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.placeholder = placeholder
        textField.addTarget(
            context.coordinator,
            action: #selector(Coordinator.textChanged(_:)),
            for: .editingChanged
        )
        textField.delegate = context.coordinator
        return textField
    }

    func updateUIView(_ textField: UITextField, context: Context) {
        if textField.text != text {
            textField.text = text
        }
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UITextFieldDelegate {
        var parent: TextFieldWrapper

        init(_ parent: TextFieldWrapper) {
            self.parent = parent
        }

        @objc func textChanged(_ sender: UITextField) {
            parent.text = sender.text ?? ""
        }

        func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
            return true
        }
    }
}

性能优化

避免不必要的视图重建

// ✅ 正确:使用 Equatable 避免不必要的更新
struct OptimizedView: View, Equatable {
    let title: String
    let count: Int

    static func == (lhs: Self, rhs: Self) -> Bool {
        lhs.title == rhs.title && lhs.count == rhs.count
    }

    var body: some View {
        Text("\(title): \(count)")
    }
}

// ✅ 正确:提取子视图减少重绘范围
struct ListView: View {
    let items: [Item]

    var body: some View {
        List {
            ForEach(items) { item in
                ItemRow(item: item)  // 单独组件,只重绘变化的部分
            }
        }
    }
}

// ❌ 错误:大视图导致整体重绘
struct MassiveView: View {
    let items: [Item]

    var body: some View {
        List {
            ForEach(items) { item in
                // 所有视图逻辑都在这里,任何变化都会导致整体重绘
            }
        }
    }
}

图像优化

// ✅ 正确:使用 AsyncImage 的 placeholder
AsyncImage(url: url) { image in
    image.resizable()
        .aspectRatio(contentMode: .fill)
} placeholder: {
    Color.gray.opacity(0.3)
        .overlay(ProgressView())
}

// ✅ 正确:指定图像缓存策略
AsyncImage(url: url, transaction: .init(animation: .easeInOut)) { phase in
    switch phase {
    case .empty:
        ProgressView()
    case .success(let image):
        image.resizable()
    case .failure:
        Image(systemName: "photo")
    @unknown default:
        EmptyView()
    }
}

延迟加载

// ✅ 正确:使用 LazyVStack/LazyHStack
ScrollView {
    LazyVStack {
        ForEach(heavyItems) { item in
            HeavyItemView(item: item)
        }
    }
}

// ✅ 正确:使用 onAppear 延迟加载
List {
    ForEach(items) { item in
        ItemRow(item: item)
            .onAppear {
                if items.last == item {
                    viewModel.loadMore()
                }
            }
    }
}

检查清单

在提交 SwiftUI 代码前,请确认:

  • 选择了正确的属性包装器(@State/@Binding/@StateObject/@ObservedObject)
  • 状态提升到合适的层级
  • ObservableObject 使用 @MainActor 标注
  • 视图组件化,没有过大的 body
  • 列表使用了 id 参数
  • 图像有 placeholder
  • 大量视图使用 LazyVStack/LazyHStack
  • 没有在主线程执行耗时操作
  • UIKit 封装正确处理了更新逻辑

参考资源

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

38.54%
按下载量换算41

Claude

29.25%
按下载量换算31

Cursor

17.38%
按下载量换算19

Gemini CLI

9.34%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

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

安装前确认

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

来源信息

继续浏览同类 Skills