Token导航 LogoToken导航TokenDH.com
开发需要联网clawhub未标认证来源可访问clear审计通过

ios-dev-skilliOS DEV 技能

Agent Skill

ios-dev-skill 用于辅助前端页面、组件、样式和交互逻辑开发,适合在 OpenClaw 中需要维护前端项目、生成组件或检查界面实现时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

2,744

周安装

111

GitHub Stars

公开资料未说明

下载量

861
OpenClaw

安装说明

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

GitHub

来源数

2

许可证

MIT-0

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

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

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

命令行安装

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

ClawHubOpenClaw
openclaw skills install ios-dev-skill

简介

提供 SwiftUI + UIKit 开发的权威参考资料合集。

  • 覆盖 MVVM/Cocoa 架构、网络层、状态管理和测试等内容。
  • 适用于需要维护前端项目或生成组件的开发场景。
  • 建议结合具体项目框架确认适用性和集成方式。
  • 安装前应核实权限范围和维护状态。ios-dev-skill 属于开发类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

name
ios-dev-skill
description
>
trigger
iOS 开发|SwiftUI|UIKit|Xcode|Swift 编程|MVVM|iOS 架构|iOS 网络|URLSession|Combine|@State|@Published|iOS 测试|XCTest|Swift 布局|SnapKit|Swift 语法|Swift 类型|Swift 闭包|Swift 泛型|Swift async|Swift await|Swift actor|Swift 代码解释|Swift optional|Swift protocol|Swift struct|Swift class|Swift enum|Swift guard|Swift if let|Swift ??|Swift @escaping|Swift 错误处理|Swift throws|Swift do-catch|Swift 访问控制|Swift extension|Swift 类型转换|Swift Sendable|Swift @propertyWrapper|Swift Property Wrapper|Swift tuple|Swift Optional 解包
tags
hermes
tags
[ios, swiftui, uikit, xcode, swift, mvvm, ios-architecture, ios-network]
related_skills
[apple-design, harmonyos-dev]
version
1.0.0
last_updated
2026-04-23
source
|
https
//developer.apple.com/documentation/swiftui
https
//developer.apple.com/documentation/uikit
https
//developer.apple.com/documentation/xcode
https
//developer.apple.com/documentation/combine
license
MIT

iOS 开发技能

iOS/macOS 应用开发技能,基于 SwiftUI + UIKit。

核心架构

MVVM 架构(SwiftUI)

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│    View     │ ←── │  ViewModel  │ ←── │   Model    │
│  (SwiftUI)  │     │ (ObservableObject) │   │   (Struct) │
└─────────────┘     └──────────────┘     └─────────────┘
     @StateObject          @Published           @State
     @ObservedObject       @State               let

数据流向

  1. View 订阅 ViewModel 的 @Published 属性
  2. ViewModel 处理业务逻辑,调用 Model
  3. Model 定义数据结构
  4. 状态变化自动触发 View 重新渲染

UIKit 架构对比

模式适用场景复杂度
MVC简单页面
MVVM中等复杂度
MVP需要解耦 View
VIPER大型模块化
Coordinator导航复杂

iOS 生命周期与状态管理

App 生命周期

状态触发时机典型用途
didFinishLaunchingApp 启动完成初始化配置
sceneWillEnterForeground从后台恢复刷新数据
sceneDidBecomeActive获得焦点恢复动画
sceneWillResignActive失去焦点暂停任务
sceneDidEnterBackground进入后台保存状态

SwiftUI 状态修饰符

@State       // 值类型,值语义
@StateObject  // 引用类型,ObservableObject
@ObservedObject // 外部提供的 ObservableObject
@EnvironmentObject // 环境注入的共享状态
@Published   // 属性观察器,自动触发更新

状态管理对比

方式适用场景生命周期
@State视图私有随视图
@StateObject模型对象随视图
@EnvironmentObject跨视图共享随 App
@AppStorageUserDefaults持久

数据持久化

方案对比

方案适用数据量类型线程安全
UserDefaults< 1MBKey-Value
FileManager任意文件
PropertyListEncoder中等结构化
SQLite.swift大型关系型
Core Data超大型对象图
Realm超大型对象

UserDefaults

@AppStorage("username") var username = ""
@AppStorage("theme") var theme = "light"

SQLite.swift

import SQLite

let db = try Connection("db.sqlite3")
let users = Table("users")
let id = Expression<Int64>("id")
let name = Expression<String>("name")

try db.run(users.insert(name <- "Alice"))
for user in try db.prepare(users) {
    print(user[name])
}

网络与 API

URLSession 封装

enum APIError: Error {
    case invalidURL, noData, decodingError, networkError(Error)
}

func fetch<T: Decodable>(_ type: T.Type, from url: String) async throws -> T {
    guard let url = URL(string: url) else { throw APIError.invalidURL }
    let (data, _) = try await URLSession.shared.data(from: url)
    do {
        return try JSONDecoder().decode(T.self, from: data)
    } catch {
        throw APIError.decodingError
    }
}

SwiftUI 网络图片

AsyncImage(url: URL(string: "https://...")) { phase in
    switch phase {
    case .empty: ProgressView()
    case .success(let image): image.resizable()
    case .failure: Image(systemName: "photo")
    @unknown default: EmptyView()
    }
}

App 分发与发布

构建配置

配置用途代码签名
Debug开发调试Development
ReleaseApp StoreDistribution
Ad Hoc测试分发Distribution

发布检查清单

  • [ ] App Icon 1024×1024
  • [ ] 启动屏(Splash Screen)
  • [ ] Info.plist 权限说明
  • [ ] 隐私政策 URL
  • [ ] TestFlight / App Store Connect 上传
  • [ ] App Store 截图(6.7 / 6.5 / 5.5 英寸)

常用权限声明

权限Info.plist Key
相机NSCameraUsageDescription
照片NSPhotoLibraryUsageDescription
位置NSLocationWhenInUseUsageDescription
通知推送证书配置

SwiftUI 基础

页面结构

@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup { ContentView() }
    }
}

struct ContentView: View {
    @State private var count = 0

    var body: some View {
        VStack(spacing: 20) {
            Text("Count: \(count)")
                .font(.largeTitle)
            Button("Increment") { count += 1 }
                .buttonStyle(.borderedProminent)
        }
    }
}

组件层级

Window → ViewController → View → Subviews
NavigationController → ViewController → TableView → Cell
TabBarController → ViewController × N → NavigationController

状态管理

状态类型SwiftUIUIKit生命周期
本地临时@Statelocal var视图存在期间
页面级@Stateview property页面存在期间
应用级@AppStorageUserDefaults跨页面持久化
全局共享@StateObjectSingleton应用生命周期

SwiftUI 状态装饰器

// @State — 值类型,组件私有
@State private var text = "Hello"

// @Binding — 双向绑定
@Binding var isPresented: Bool

// @StateObject — 引用类型,视图拥有
@StateObject private var viewModel = ViewModel()

// @ObservedObject — 引用类型,外部传入
@ObservedObject var viewModel: ViewModel

// @EnvironmentObject — 环境注入的全局状态
@EnvironmentObject var authService: AuthService

// @AppStorage — 持久化
@AppStorage("username") var username = ""

UIKit 状态

// 局部变量
class ViewController: UIViewController {
    private var data: [String] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        data = loadData()
    }
}

// 视图属性
class ViewController: UIViewController {
    var initialData: [String] = []
}

// UserDefaults
UserDefaults.standard.string(forKey: "username")

// Singleton
let shared = NetworkManager.shared

Navigation 导航模式

SwiftUI NavigationStack(推荐)

NavigationStack {
    List(users) { user in
        NavigationLink(destination: UserDetailView(user: user)) {
            Text(user.name)
        }
    }
}

UIKit 导航

// 导航控制器
let nav = UINavigationController(rootViewController: HomeVC())
nav.pushViewController(detailVC, animated: true)
nav.popViewController(animated: true)

// TabBar 切换
UITabBarController()
  ├─ UINavigationController(首页)
  ├─ UINavigationController(发现)
  └─ UINavigationController(我的)

网络层

SwiftUI + async/await

actor NetworkService {
    static let shared = NetworkService()

    func fetch<T: Decodable>(_ type: T.Type, from url: URL) async throws -> T {
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode(T.self, from: data)
    }
}

// 使用
Task {
    let users = try await NetworkService.shared.fetch([User].self, from: url)
}

UIKit + async/await

class NetworkManager {
    static let shared = NetworkManager()

    func request<T: Decodable>(_ type: T.Type, endpoint: String) async throws -> T {
        guard let url = URL(string: endpoint) else {
            throw NetworkError.invalidURL
        }
        let (data, _) = try await URLSession.shared.data(from: url)
        return try JSONDecoder().decode(T.self, from: data)
    }
}

URLSession 完整示例

import Foundation

struct User: Codable, Identifiable {
    let id: String
    let name: String
    let email: String
}

enum NetworkError: Error {
    case invalidURL
    case requestFailed
    case decodingFailed
    case noData
}

class APIClient {
    private let baseURL = "https://api.example.com"
    private let session: URLSession

    init() {
        let config = URLSessionConfiguration.default
        config.timeoutIntervalForRequest = 30
        self.session = URLSession(configuration: config)
    }

    func get<T: Codable>(_ type: T.Type, path: String) async throws -> T {
        guard let url = URL(string: baseURL + path) else {
            throw NetworkError.invalidURL
        }

        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let (data, response) = try await session.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw NetworkError.requestFailed
        }

        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase

        do {
            return try decoder.decode(T.self, from: data)
        } catch {
            throw NetworkError.decodingFailed
        }
    }

    func post<T: Codable, B: Encodable>(_ type: T.Type, path: String, body: B) async throws -> T {
        guard let url = URL(string: baseURL + path) else {
            throw NetworkError.invalidURL
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        let encoder = JSONEncoder()
        encoder.keyEncodingStrategy = .convertToSnakeCase
        request.httpBody = try encoder.encode(body)

        let (data, response) = try await session.data(for: request)

        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw NetworkError.requestFailed
        }

        return try JSONDecoder().decode(T.self, from: data)
    }
}

依赖注入

SwiftUI Environment 注入

struct ContentView: View {
    @EnvironmentObject var authService: AuthService
    var body: some View { ... }
}

// App 层级注入
ContentView()
    .environmentObject(AuthService())

UIKit Protocol 注入

protocol NetworkServiceProtocol {
    func fetchUsers() async throws -> [User]
}

class ViewModel {
    let networkService: NetworkServiceProtocol
    init(networkService: NetworkServiceProtocol = NetworkService.shared) {
        self.networkService = networkService
    }
}

Combine 响应式编程

Publisher 与 Subscriber

import Combine

// Publisher
let publisher = PassthroughSubject<String, Never>()

// Subscriber
let cancellable = publisher
    .filter { $0.count > 3 }
    .map { $0.uppercased() }
    .sink { print($0) }

// Future + Promise
func fetchUser(id: Int) -> Future<User, Error> {
    Future { promise in
        // 异步操作
        promise(.success(user))
    }
}

SwiftUI + Combine

@Published var searchText: String = ""

var searchResults: AnyPublisher<[User], Never> {
    $searchText
        .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
        .removeDuplicates()
        .flatMap { query in
            query.isEmpty ? Just([]).eraseToAnyPublisher()
                         : api.search(query: query)
        }
        .receive(on: DispatchQueue.main)
        .eraseToAnyPublisher()
}

### AnyCancellable 内存管理

import Combine

class ViewModel { private var cancellables = Set<AnyCancellable>()

func bind() { $searchText .debounce(for: .milliseconds(300), scheduler: RunLoop.main) .sink { [weak self] text in self?.performSearch(text) } .store(in: &cancellables) } }

// Store in property class AnotherViewModel { @Published var data: [Item] = []

private var cancellables = Set<AnyCancellable>()

func subscribe(to api: APIService) { api.itemsPublisher .receive(on: DispatchQueue.main) .sink { [weak self] items in self?.data = items } .store(in: &cancellables) } }

// 取消订阅 cancellables.removeAll() // 手动取消所有


### 常用 Operators

| Operator | 用途 |
|----------|------|
| `map` | 转换值 |
| `filter` | 过滤值 |
| `flatMap` | 展平嵌套 Publisher |
| `debounce` | 防抖(搜索场景) |
| `throttle` | 节流(滚动场景) |
| `removeDuplicates` | 去重 |
| `combineLatest` | 合并多个 Publisher |
| `merge` | 合并同类型 Publisher |
| `catch` | 错误处理 |
| `retry` | 重试 |
| `zip` | 配对组合 |

---

# 性能优化

| 场景 | SwiftUI | UIKit |
|------|---------|-------|
| 列表滚动 | LazyVStack | UITableView/UICollectionView |
| 图片缓存 | AsyncImage + 第三方库 | SDWebImage/Kingfisher |
| 预取数据 | .task modifier | UITableViewDataSourcePrefetching |
| 后台任务 | Task.detached | async/await |

### SwiftUI 列表优化

// ✅ 推荐:LazyVStack List { ForEach(items) { item in ItemView(item: item) } }

// ❌ 避免:大列表不用 Lazy VStack { ForEach(items) { item in // 全部渲染 ItemView(item: item) } }


### UIKit 列表优化

// UICollectionView 预加载 func collectionView(_ collectionView: UICollectionView, prefetchItemsAt indexPaths: [IndexPath]) { for indexPath in indexPaths { let item = items[indexPath.item] imageLoader.prefetch(url: item.imageURL) } }


---

# 测试策略

单元测试 → ViewModel / Service 逻辑 ↓ UI 测试 → View 渲染 + 交互(XCUITest) ↓ 集成测试 → 模块间交互 ↓ 快照测试 → UI 视觉回归(swift-snapshot-testing)


### Swift 单元测试示例

import XCTest

final class UserViewModelTests: XCTestCase { var viewModel: UserListViewModel! var mockService: MockNetworkService!

override func setUp() { super.setUp() mockService = MockNetworkService() viewModel = UserListViewModel(networkService: mockService) }

func testLoadUsersSuccess() async { // Given mockService.users = [User(id: "1", name: "John")]

// When await viewModel.loadUsers()

// Then XCTAssertEqual(viewModel.users.count, 1) XCTAssertFalse(viewModel.isLoading) } }


---

# 完整页面示例

### SwiftUI + MVVM

// Model struct User: Identifiable, Codable { let id: String let name: String let email: String }

// ViewModel @MainActor class UserListViewModel: ObservableObject { @Published var users: [User] = [] @Published var isLoading = false @Published var error: String?

func loadUsers() async { isLoading = true defer { isLoading = false } do { users = try await api.fetch(User.self, path: "/users") } catch { self.error = error.localizedDescription } } }

// View struct UserListView: View { @StateObject private var vm = UserListViewModel()

var body: some View { NavigationStack { Group { if vm.isLoading { ProgressView() } else if let error = vm.error { Text("Error: \(error)") .foregroundColor(.red) } else { List(vm.users) { user in NavigationLink(destination: UserDetailView(user: user)) { HStack { Text(user.name) Spacer() Text(user.email) .foregroundColor(.secondary) } } } } } .navigationTitle("用户") .task { await vm.loadUsers() } } } }


### UIKit + MVC

import UIKit import SnapKit

class UserListViewController: UIViewController { private let tableView = UITableView(frame: .zero, style: .insetGrouped) private var users: [User] = []

override func viewDidLoad() { super.viewDidLoad() setupUI() loadData() }

private func setupUI() { title = "用户" view.backgroundColor = .systemGroupedBackground

tableView.delegate = self tableView.dataSource = self tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") view.addSubview(tableView)

tableView.snp.makeConstraints { make in make.edges.equalToSuperview() } }

private func loadData() { Task { do { users = try await APIClient.shared.get([User].self, path: "/users") tableView.reloadData() } catch { showError(error) } } } }

extension UserListViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return users.count }

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) let user = users[indexPath.row] var config = cell.defaultContentConfiguration() config.text = user.name config.secondaryText = user.email cell.contentConfiguration = config return cell }

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let user = users[indexPath.row] let detailVC = UserDetailViewController(user: user) navigationController?.pushViewController(detailVC, animated: true) } }


---

# Swift 语言权威参考

> 来源:The Swift Programming Language (6.3)
> https://docs.swift.org/swift-book/documentation/the-swift-programming-language/
> CC BY 4.0 License

## 类型系统

### 基本类型

| 类型 | 说明 | 示例 |
|------|------|------|
| Int | 整数 | `42`, `-7` |
| Double | 64位浮点 | `3.14159` |
| Float | 32位浮点 | `3.14` |
| Bool | 布尔 | `true` / `false` |
| String | 字符串 | `"Hello"` |
| Character | 单字符 | `"A"` |

### 类型推断与注解

let inferred = 42 // Int let annotated: Int = 42 // 显式 Int let pi: Double = 3.14 // Double


### 类型别名

typealias AudioSample = UInt16 typealias Callback = (Int, String) -> Void


## Optional 可选类型

### 定义与解包

// 定义 var serverResponse: String? = nil var response: String! = nil // 隐式解包

// 解包方式 if let value = optional { print(value) }

// guard 解包 func process(_ value: String?) { guard let value = value else { return } print(value) }

// ?? 操作符 let name = optional ?? "default"

// 链式调用 let upper = optional?.uppercased()


### Optional 模式

// switch 模式匹配 switch optional { case .some(let value): print(value) case .none: print("nil") }

// 问号链式调用 person?.address?.city


##  Tuple 元组

// 定义 let httpError = (404, "Not Found") let (code, message) = httpError let onlyCode = httpError.0

// 命名 let success = (code: 200, message: "OK") success.code success.message

// 返回多值 func getUser() -> (name: String, age: Int) { return ("Alice", 30) }


## 集合类型

### Array

// 创建 var arr = [Int]() // 空 var arr2 = Array(repeating: 0, count: 5) // [0,0,0,0,0] let literals = [1, 2, 3] // 字面量

// 操作 arr.append(4) arr.insert(0, at: 0) arr.remove(at: 0) arr.removeLast() arr.first arr.last

// 遍历 for item in arr { } for (i, v) in arr.enumerated() { }


### Set

// 创建 var set = Set<Int>() let genres: Set<String> = ["Rock", "Jazz"]

// 操作 set.insert("Pop") set.remove("Rock") set.contains("Jazz")

// 集合运算 a.union(b) // 并集 a.intersection(b) // 交集 a.subtracting(b) // 差集 a.symmetricDifference(b) // 对称差集

// 关系 a.isSubset(of: b) a.isSuperset(of: b) a.isDisjoint(with: b)


### Dictionary

// 创建 var dict = [String: Int]() let capitals = ["CN": "Beijing", "JP": "Tokyo"]

// 操作 dict["key"] = "value" dict["key"] = nil // 删除 dict.updateValue("v", forKey: "k") // 返回旧值

// 安全访问 if let value = dict["key"] { }

// 遍历 for (k, v) in dict { } for key in dict.keys { } for value in dict.values { }


## 函数

### 定义与调用

func greet(name: String) -> String { return "Hello, \(name)" } greet(name: "World")

// 参数标签 func greet(to name: String) -> String { return "Hello, \(name)" } greet(to: "World")

// 默认参数 func greet(_ name: String = "World") -> String { return "Hello, \(name)" }

// 可变参数 func sum(_ numbers: Int...) -> Int { return numbers.reduce(0, +) } sum(1, 2, 3, 4, 5)

// inout 参数 func swap(_ a: inout Int, _ b: inout Int) { let temp = a a = b b = temp }


### 函数类型

var mathFunc: (Int, Int) -> Int = { $0 + $1 }

// 作为参数 func apply(_ op: (Int, Int) -> Int, _ a: Int, _ b: Int) -> Int { return op(a, b) } apply(mathFunc, 3, 4)

// 作为返回值 func choose(_ op: Bool) -> (Int, Int) -> Int { return op ? { $0 + $1 } : { $0 - $1 } }


### 嵌套函数

func outer() -> () -> Int { var count = 0 func inner() -> Int { count += 1 return count } return inner }


## 闭包

### 基本语法

// 完整语法 { (params) -> ReturnType in statements }

// 类型推断 { a, b in a + b }

// 无参数 { () -> Int in 42 }

// 返回类型推断 { $0 + $1 }


### 尾随闭包

// 不用尾随 arr.map({ (x: Int) -> Int in x * 2 })

// 尾随闭包 arr.map { $0 * 2 }

// 最后一个参数是闭包 arr.map { x in x * 2 }


### @escaping

var handlers: [() -> Void] = []

func withEscaping(_ handler: @escaping () -> Void) { handlers.append(handler) }

func withoutEscaping(_ handler: () -> Void) { handler() }

// 逃逸闭包需要显式 self class MyClass { var x = 10 func test() { withEscaping { self.x = 20 } // 必须显式 withoutEscaping { x = 30 } // 可省略 } }


### 捕获

func makeCounter() -> () -> Int { var count = 0 return { count += 1 return count } } let counter = makeCounter() counter() // 1 counter() // 2


## 枚举

enum Direction { case north, south, east, west }

let dir: Direction = .north

// 关联值 enum Result { case success(Data) case failure(Error) }

// 方法 enum Device { case phone, tablet func description() -> String { switch self { case .phone: return "iPhone" case .tablet: return "iPad" } } }

// 原始值 enum ASCIIControl: Character { case tab = "\ " case newline = "\ " }


## 结构体与类

### 对比

| 特性 | struct | class |
|------|--------|-------|
| 类型 | 值类型 | 引用类型 |
| 继承 | ❌ | ✅ |
| 初始化 | 自动生成 | 手动 |
| 析构 | — | ✅ |
| 引用计数 | — | ✅ |

struct Point { var x: Double var y: Double // 自动生成 memberwise init }

class Person { var name: String var age: Int init(name: String, age: Int) { self.name = name self.age = age } }


## 属性

### 存储属性

struct FixedRange { var start: Int let end: Int // 常量 }


### 计算属性

struct Rect { var origin: Point var size: Size var center: Point { get { Point(x: origin.x + size.width/2, y: origin.y + size.height/2) } set { origin.x = newValue.x - size.width/2 origin.y = newValue.y - size.height/2 } } }


### 属性包装器

@propertyWrapper struct SmallNumber { private var number: Int var value: Int { get { min(number, 12) } set { number = newValue } } init() { number = 0 } init(wrappedValue: Int) { number = min(wrappedValue, 12) } }

@SmallNumber var value: Int // 使用


### 属性观察者

class StepCounter { var totalSteps: Int = 0 { willSet { print("will set to \(newValue)") } didSet { print("did set from \(oldValue)") } } }


### 懒加载

class DataManager { lazy var importer = DataImporter() // 首次访问时才创建 }


## 方法

### 实例方法

class Counter { var count = 0 func increment() { count += 1 } func increment(by amount: Int) { count += amount } func reset() { count = 0 } }


### 静态/类方法

struct MathUtils { static func sqrt(_ n: Double) -> Double { ... } } MathUtils.sqrt(16)

// 类方法(可被重写) class Animal { class func info() { print("Animal") } }


## 下标

struct TimesTable { subscript(index: Int) -> Int { return index * multiplier } } let table = TimesTable(multiplier: 3) table[6] // 18

// 多维下标 struct Matrix { subscript(row: Int, col: Int) -> Double { get { return grid[row * 3 + col] } set { grid[row * 3 + col] = newValue } } }


## 继承

class Vehicle { var speed = 0 func describe() -> String { "speed: \(speed)" } }

class Bicycle: Vehicle { var hasBasket = false override func describe() -> String { // 调用父类 return super.describe() + ", basket: \(hasBasket)" } }

// final 类不可被继承 final class FinalClass { }


## 初始化与析构

### 初始化

class ShoppingListItem { var name: String var quantity: Int = 1 var completed: Bool = false

init(name: String, quantity: Int = 1) { self.name = name self.quantity = quantity } }

// 可失败初始化 struct Animal { let species: String init?(species: String) { if species.isEmpty { return nil } self.species = species } }


### 析构

class FileHandler { var file: FileHandle init() { file = open(...) } deinit { file.close() } }


# 错误处理

## 错误处理

// 定义错误 enum NetworkError: Error { case badURL case noData case decodingFailed }

// 抛出 func fetch() throws -> Data { guard let url = URL(string: "...") else { throw NetworkError.badURL } return try Data(contentsOf: url) }

// 处理 do { let data = try fetch() } catch NetworkError.badURL { print("Bad URL") } catch { print("Error: \(error)") }

// try? 转换 Optional let data = try? fetch()

// try! 强制解包(危险) let data = try! fetch()


# 协议与泛型

## 协议

### 定义与遵循

protocol ExampleProtocol { var simpleDescription: String { get } mutating func adjust() }

// 遵循 struct SimpleStructure: ExampleProtocol { var simpleDescription: String = "A simple structure" mutating func adjust() { } }

// 类遵循 class SimpleClass: ExampleProtocol { var simpleDescription: String = "A simple class" func adjust() { } }


### 协议扩展

extension Collection { func allEven() -> [Element] where Element: Numeric { return self.filter { ($0 as? Int ?? 0) % 2 == 0 } } }


## 泛型

### 函数泛型

func swapTwoValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } swapTwoValues(&x, &y)


### 类型约束

func findIndex<T: Equatable>(of valueToFind: T, in array: [T]) -> Int? { for (index, value) in array.enumerated() { if value == valueToFind { return index } } return nil }


### 泛型类型

struct Stack<Element> { var items: [Element] = [] mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { items.removeLast() } }


### where 子句

func allItemsMatch<C1: Container, C2: Container> (_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.Element == C2.Element, C1.Element: Equatable { // ... }


## 访问控制

| 修饰符 | 范围 |
|--------|------|
| open | 任意模块,可被继承 |
| public | 任意模块 |
| internal | 模块内(默认) |
| fileprivate | 当前文件 |
| private | 当前作用域 |

public class PublicClass { private var privateVar = 0 fileprivate var fileVar = 0 }


## 扩展

extension Int { var isEven: Bool { return self % 2 == 0 } func repetitions(_ task: () -> Void) { for _ in 0..<self { task() } } }

5.isEven // true 3.repetitions { print("Hello") }


## 类型转换

// 类型检查 if item is String { print("String") }

// 向下转型 if let str = item as? String { print(str) }

// 强制转型(危险) let str = item as! String

// Any 和 AnyObject var things: [Any] = [] things.append(42) things.append("string")


## 嵌套类型

struct ChessBoard { enum Piece { case king, queen, rook, bishop, knight, pawn } var board: [[Piece?]] }

let piece: ChessBoard.Piece = .king


# Swift 6 并发

## Swift 6 Concurrency

### async/await

func fetchData() async throws -> Data { ... }

Task { do { let data = try await fetchData() } catch { print(error) } }

// async let 并行 async let first = fetchData() async let second = anotherFetch() let results = await [first, second]


### Task

// 创建 let task = Task { await doWork() } let result = await task.value task.cancel()

// TaskGroup await withTaskGroup(of: Data.self) { group in for url in urls { group.addTask { await fetch(url) } } var results: [Data] = [] for await data in group { results.append(data) } }


### Actor

actor SafeCounter { private var count = 0 func increment() { count += 1 } func getCount() -> Int { count } }

// MainActor @MainActor func updateUI() { // UI 更新 }


### Sendable

struct User: Sendable { let id: String }

actor SafeLogger: Sendable { // actor 自动 Sendable }

---

## 避坑指南

### 常见错误

| 错误做法 | 正确做法 |
|---------|---------|
| ❌ 在主线程执行网络请求 | ✅ async/await 自动后台执行 |
| ❌ 不处理网络错误 | ✅ always try-catch + user feedback |
| ❌ @State 用于引用类型 | ✅ @StateObject 用于 class |
| ❌ 不用 LazyVStack 处理大列表 | ✅ 懒加载避免性能问题 |
| ❌ 硬编码 URL | ✅ Configuration/Environment |

### SwiftUI 陷阱

- ⚠️ **@State 复制语义** — @State 修饰的 struct 是值语义,修改会触发重渲染
- ⚠️ **@StateObject 只初始化一次** — 不能在 body 中创建
- ⚠️ **onAppear vs task** — task 可取消,onAppear 不行

### UIKit 陷阱

- ⚠️ **循环引用** — delegate/closure 记得用 [weak self]
- ⚠️ **主线程 UI** — UI 更新必须在主线程
- ⚠️ **Memory Leak** — 及时清理 NotificationCenter 观察者

---

## 来源

> 来源:Apple Developer Documentation(2026-04-23 访问)
> - SwiftUI: https://developer.apple.com/documentation/swiftui
> - UIKit: https://developer.apple.com/documentation/uikit
> - Xcode: https://developer.apple.com/documentation/xcode
> - Combine: https://developer.apple.com/documentation/combine
>
> 更新频率:随 Xcode/iOS 版本迭代

---

# 持久化

### UserDefaults

适用于:小量配置、用户偏好、简单状态

// SwiftUI @AppStorage("username") var username = "" @AppStorage("isDarkMode") var isDarkMode = false

// 代码直接访问 UserDefaults.standard.string(forKey: "username") UserDefaults.standard.set("value", forKey: "key")


### SQLite(生产推荐)

适用于:结构化数据、离线存储、查询性能

import SQLite

class DatabaseManager { static let shared = DatabaseManager() private var db: Connection?

// 表定义 private let users = Table("users") private let id = SQLite.Expression<Int64>("id") private let name = SQLite.Expression<String>("name") private let email = SQLite.Expression<String>("email")

init() { do { let path = NSSearchPathForDirectoriesInDomains( .documentDirectory, .userDomainMask, true ).first! db = try Connection("\(path)/sqlite.db") try createTables() } catch { print("Database error: \(error)") } }

private func createTables() throws { try db?.run(users.create(ifNotExists: true) { t in t.column(id, primaryKey: .autoincrement) t.column(name) t.column(email) }) }

// CRUD func insertUser(_ user: User) throws { let insert = users.insert( name <- user.name, email <- user.email ) try db?.run(insert) }

func fetchUsers() throws -> [User] { guard let db = db else { return [] } return try db.prepare(users).map { row in User( id: row[id], name: row[name], email: row[email] ) } }

func deleteUser(_ userId: Int64) throws { let user = users.filter(id == userId) try db?.run(user.delete()) } }


### Core Data(苹果官方)

适用于:复杂对象图、大量关系数据、Apple 生态深度集成

// Core Data Stack class CoreDataManager { static let shared = CoreDataManager()

lazy var persistentContainer: NSPersistentContainer = { let container = NSPersistentContainer(name: "Model") container.loadPersistentStores { _, error in if let error = error { fatalError("Core Data failed: \(error)") } } container.viewContext.automaticallyMergesChangesFromParent = true return container }()

var viewContext: NSManagedObjectContext { persistentContainer.viewContext }

func save() { let context = viewContext if context.hasChanges { do { try context.save() } catch { print("Save error: \(error)") } } } }

// SwiftUI 集成 struct ContentView: View { @Environment(\.managedObjectContext) var viewContext

@FetchRequest( sortDescriptors: [NSSortDescriptor(keyPath: \User.name, ascending: true)], animation: .default ) var users: FetchedResults<User>

var body: some View { List(users, id: \.self) { user in Text(user.name ?? "Unknown") } } }


---

# Swift Concurrency 深度

### Sendable 协议

确保数据可以安全跨并发域传递。

// ✅ 可Sendable的类型 struct User: Sendable { let id: String let name: String // 值类型默认 Sendable }

// ⚠️ Class 需要手动实现 final class SafeClass: @unchecked Sendable { // 不做线程安全假设,仅用于已知安全的场景 }

// ❌ 不可Sendable class UnsafeClass { var cache = [String: Any]() // 包含可变状态 }


### MainActor

确保代码在主线程执行,用于 UI 更新。

// 方法级别 @MainActor func updateUI() { // 自动在主线程执行 self.username = "New Name" }

// 类级别(所有方法默认主线程) @MainActor class ViewModel: ObservableObject { @Published var items: [Item] = []

// 隐式 @MainActor func loadItems() async { let fetched = await network.fetchItems() self.items = fetched // 安全 } }

// 非隔离函数访问主线程数据 nonisolated func describe(_ vm: ViewModel) { // ❌ 不能访问 @Published // ✅ 可以访问 Sendable 属性 print("Description") }


### TaskGroup

并发执行多个任务。

// 并发下载 func fetchAllImages(urls: [URL]) async throws -> [Data] { try await withThrowingTaskGroup(of: Data.self) { group in for url in urls { group.addTask { let (data, _) = try await URLSession.shared.data(from: url) return data } }

var results: [Data] = [] for try await data in group { results.append(data) } return results } }

// 带取消 func fetchWithCancel(urls: [URL]) async { await withTaskGroup(of: Data?.self) { group in for url in urls { group.addTask { try? await Task.sleep(nanoseconds: 1_000_000_000) guard !Task.isCancelled else { return nil } let (data, _) = try await URLSession.shared.data(from: url) return data } } } }


### Task 取消

// 检查取消 func performWork() async throws { for item in items { try Task.checkCancellation() // 抛出 CancellationError // 处理 item } }

// withTaskCancellationHandler try await withTaskCancellationHandler { try await longRunningWork() } onCancel: { cleanup() }

// 传递取消 struct DetailView: View { @State private var data: Data? @Environment(\.dismiss) var dismiss

var body: some View { Button("加载") { Task { data = await fetchData() } } .onDisappear { // 视图消失时自动取消 } } }


---

# UIKit 进阶

### UICollectionView

生产级列表/网格首选。

class CollectionViewController: UIViewController { private var collectionView: UICollectionView! private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!

enum Section: Hashable { case main case featured }

override func viewDidLoad() { super.viewDidLoad() setupCollectionView() configureDataSource() applySnapshot() }

private func setupCollectionView() { // Compositional Layout let config = UICollectionLayoutConfiguration( -interSectionSpacing: 16 ) let layout = UICollectionViewCompositionalLayout( sectionProvider: { sectionIndex, environment in let itemSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(0.5), heightDimension: .fractionalHeight(1.0) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) item.contentInsets = NSDirectionalEdgeInsets( top: 8, leading: 8, bottom: 8, trailing: 8 )

let groupSize = NSCollectionLayoutSize( widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(180) ) let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, subitems: [item] )

let section = NSCollectionLayoutSection(group: group) section.contentInsets = NSDirectionalEdgeInsets( top: 0, leading: 16, bottom: 16, trailing: 16 )

return NSCollectionLayoutSection(section: section) }, configuration: config )

collectionView = UICollectionView( frame: view.bounds, collectionViewLayout: layout ) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] collectionView.delegate = self view.addSubview(collectionView) }

private func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration< UICollectionViewCell, Item > { cell, indexPath, item in var config = UIListContentConfiguration.cell() config.text = item.title config.secondaryText = item.subtitle config.image = UIImage(systemName: item.icon) cell.contentConfiguration = config }

dataSource = UICollectionViewDiffableDataSource<Section, Item>( collectionView: collectionView ) { collectionView, indexPath, item in collectionView.dequeueConfiguredReusableCell( using: cellRegistration, for: indexPath, item: item ) } }

private func applySnapshot() { var snapshot = NSDiffableDataSourceSnapshot<Section, Item>() snapshot.appendSections([.main]) snapshot.appendItems(items) dataSource.apply(snapshot, animatingDifferences: true) } }

extension CollectionViewController: UICollectionViewDelegate { func collectionView( _ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath ) { guard let item = dataSource.itemIdentifier(for: indexPath) else { return } // 处理选择 } }


### Auto Layout 完整约束

// NSLayoutConstraint 语法 label.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 16), label.heightAnchor.constraint(greaterThanOrEqualToConstant: 44) ])

// 优先级 let highPriority = label.widthAnchor.constraint(equalToConstant: 100) highPriority.priority = .defaultHigh // 750

let lowPriority = label.widthAnchor.constraint(equalToConstant: 50) lowPriority.priority = .defaultLow // 250

// 比例约束 label.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5)

// 尺寸约束 label.heightAnchor.constraint(equalTo: label.widthAnchor, multiplier: 1.5)


### 键盘处理

class KeyboardViewController: UIViewController { @IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var textField: UITextField!

override func viewDidLoad() { super.viewDidLoad() setupKeyboardObservers() }

private func setupKeyboardObservers() { NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil ) }

@objc func keyboardWillShow(_ notification: Notification) { guard let keyboardFrame = notification.userInfo?[ UIResponder.keyboardFrameEndUserInfoKey ] as? CGRect else { return }

let contentInsets = UIEdgeInsets( top: 0, left: 0, bottom: keyboardFrame.height, right: 0 ) scrollView.contentInset = contentInsets scrollView.scrollIndicatorInsets = contentInsets }

@objc func keyboardWillHide(_ notification: Notification) { scrollView.contentInset = .zero scrollView.scrollIndicatorInsets = .zero }

@objc func dismissKeyboard() { view.endEditing(true) } }

// SwiftUI 版本 struct KeyboardAvoidingView: View { @State private var text = "" @FocusState private var isFocused: Bool

var body: some View { ScrollView { TextField("输入", text: $text) .focused($isFocused) .padding() .background(Color.gray.opacity(0.2)) } .onTapGesture { isFocused = false } } }


---

## Swift Concurrency 避坑

### 常见错误

| 错误做法 | 正确做法 |
|---------|---------|
| ❌ nonisolated 函数访问 @Published | ✅ 用 @MainActor 包装 |
| ❌ 跨线程传递 UIView | ✅ 始终在主线程操作 |
| ❌ Task 不保存引用 | ✅ 存储 Task 以支持取消 |
| ❌ 忘记 CancellationError | ✅ 调用 Task.checkCancellation() |
| ❌ actor 内部用锁 | ✅ actor 天然线程安全 |
| ❌ 传递非 Sendable 闭包 | ✅ 确保闭包捕获值是 Sendable |

### @MainActor 传递规则

@MainActor class ViewModel { func update() { /* 主线程 */ } }

// ✅ 正确:await 后自动回到主线程 let vm = ViewModel() Task { @MainActor in await someAsyncMethod() vm.update() // 安全 }

// ❌ 错误:非隔离上下文访问 Task { await someAsyncMethod() // vm.update() // ❌ 编译错误 }


---

# Widget 开发

- [widget.md](references/widget.md) — TimelineProvider / App Group / Interactive Widget / Lock Screen Widget

# 国际化与本地化

- [localization.md](references/localization.md) — NSLocalizedString / String Catalog / 格式化 / RTL / App Store 本地化

# Swift Concurrency 权威参考

- [swift-concurrency.md](references/swift-concurrency.md) — async/await / TaskGroup / MainActor / Actor / Sendable / Swift 6

## 快速参考

### SwiftUI 状态装饰器速查

| 装饰器 | 作用域 | 父传子 | 创建者 |
|--------|--------|--------|--------|
| @State | 局部 | ❌ | 视图 |
| @Binding | 局部 | ✅ | 视图 |
| @StateObject | 局部 | ❌ | 视图 |
| @ObservedObject | 局部 | ✅ | 父视图 |
| @EnvironmentObject | 全局 | ✅ | 任意 |
| @AppStorage | 全局 | ✅ | UserDefaults |
| @SceneStorage | 全局 | ✅ | Scene |
| @FocusState | 局部 | ✅ | 视图 |
| @ScaledMetric | 局部 | ✅ | 视图 |

### UIKit vs SwiftUI 生命周期

| 阶段 | UIKit | SwiftUI |
|------|-------|---------|
| 创建 | `init` | `@State init` |
| 加载视图 | `loadView` | body |
| 视图加载 | `viewDidLoad` | `.task` |
| 即将显示 | `viewWillAppear` | `.onAppear` |
| 已显示 | `viewDidAppear` | — |
| 即将消失 | `viewWillDisappear` | `.onDisappear` |
| 已消失 | `viewDidDisappear` | — |
| 内存警告 | `didReceiveMemoryWarning` | `.onChange` |

### iOS 版本支持速查

| API | 最低版本 |
|-----|---------|
| NavigationStack | iOS 16+ |
| @MainActor | iOS 16+ / Swift 5.5+ |
| SwiftUI Charts | iOS 16+ |
| AnyCancellable store | iOS 13+ |
| AsyncSequence | Swift 5.5+ |
| WidgetKit | iOS 14+ |
| Live Activities | iOS 16.1+ |
| Interactive Widget | iOS 17+ |

### Auto Layout 速查

// 核心约束 label.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16), label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16), label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), label.heightAnchor.constraint(greaterThanOrEqualToConstant: 44) ])

// SnapKit view.snp.makeConstraints { make in make.edges.equalToSuperview().inset(16) make.height.greaterThanOrEqualTo(100) make.width.equalToSuperview().multipliedBy(0.5) }

// 优先级 .widthAnchor.constraint(equalToConstant: 100).priority = .defaultHigh // 750 .widthAnchor.constraint(equalToConstant: 50).priority = .defaultLow // 250 .widthAnchor.constraint(equalToConstant: 0).priority = .required // 1000


### 网络状态速查

| 状态 | SwiftUI | UIKit |
|------|---------|-------|
| 空闲 | `isLoading = false` | `state = .idle` |
| 加载中 | `isLoading = true` | `state = .loading` |
| 成功 | `@Published var items` | `delegate?.didFinish` |
| 错误 | `@Published var error` | `delegate?.didFail` |

### Combine 操作符速查

| 操作符 | 用途 | 示例 |
|--------|------|------|
| `map` | 转换值 | `.map { $0 * 2 }` |
| `filter` | 过滤 | `.filter { $0 > 0 }` |
| `flatMap` | 展平 | `.flatMap { $0.publisher }` |
| `debounce` | 防抖 | `.debounce(for: .milliseconds(300), scheduler: RunLoop.main)` |
| `throttle` | 节流 | `.throttle(for: .seconds(1), scheduler: RunLoop.main, latest: true)` |
| `combineLatest` | 合并 | `Publishers.CombineLatest(a, b)` |
| `merge` | 合并同类型 | `a.merge(with: b)` |
| `catch` | 错误处理 | `.catch { Just(default) }` |
| `retry` | 重试 | `.retry(3)` |
| `zip` | 配对 | `a.zip(b)` |

### Auto Layout 速查

// 核心约束 label.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16) label.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16) label.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor) label.heightAnchor.constraint(greaterThanOrEqualToConstant: 44)

// SnapKit view.snp.makeConstraints { make in make.edges.equalToSuperview().inset(16) make.height.greaterThanOrEqualTo(100) }

// 优先级 .widthAnchor.constraint(equalToConstant: 100).priority = .defaultHigh .widthAnchor.constraint(equalToConstant: 50).priority = .defaultLow


### Widget 尺寸速查

| 尺寸 | 宽度 | 高度 | 用途 |
|------|------|------|------|
| systemSmall | 155pt | 155pt | 单指标 |
| systemMedium | 329pt | 155pt | 双指标 |
| systemLarge | 329pt | 345pt | 列表卡片 |
| accessoryCircular | — | — | 锁屏圆形 |
| accessoryRectangular | — | — | 锁屏矩形 |

### 常用尺寸速查

| 场景 | 尺寸 |
|------|------|
| 最小点击区域 | 44pt |
| 标准间距 | 16pt |
| 大间距 | 24pt |
| 安全区留边 | 16pt |
| TabBar 高度 | 49pt |
| NavigationBar 高度 | 44pt |
| Widget 圆角 | 20pt |
| 按钮圆角 | 8pt |
| 图片圆角 | 12pt |

### Swift Concurrency 速查

// async/await func fetch() async throws -> Data

// Task Task { await fetch() } Task.detached { await fetch() }

// TaskGroup await withTaskGroup(of: Data.self) { group in group.addTask { await fetch() } }

// MainActor @MainActor func update() { } Task { @MainActor in update() }

// Sendable struct User: Sendable { let id: String } actor SafeCounter { }

// 取消 Task.checkCancellation() Task.isCancelled task.cancel()


### 生命周期速查

| 事件 | SwiftUI | UIKit |
|------|---------|-------|
| 视图出现 | `.onAppear` | `viewDidAppear` |
| 视图消失 | `.onDisappear` | `viewDidDisappear` |
| 应用激活 | `.onReceive` | `applicationDidBecomeActive` |
| 应用休眠 | — | `applicationWillResignActive` |



## 输出格式规范

当使用本技能回答用户问题时,遵循以下格式:

### 回复结构
1. **直接回答** — 一段简洁的话给出核心答案
2. **代码示例** — 提供完整的 SwiftUI/UIKit 代码(如需)
3. **实现要点** — 关键步骤和注意事项
4. **避坑提醒** — 常见错误+正确做法

### 示例回复(网络请求)

> SwiftUI 推荐使用 async/await 处理网络请求。定义一个 `NetworkService` actor 封装 `URLSession`,在 ViewModel 中用 `@Published` 管理状态。示例:定义 `fetch<T: Decodable>` 泛型方法,用 `Task` 调用并更新 `@Published` 属性。错误处理用 `do-catch`,始终给用户反馈。

### 禁用格式
- ❌ 不要显式分层(避免"第一层/第二层/框架分析"等字眼)
- ❌ 不要长篇解释概念,要直接给出实现
- ❌ 不要只给代码片段,要给完整可运行的示例
- ✅ 输出应是一段干净的话 + 完整代码

适合场景

01

OpenClaw 用户查找和安装 Skill 时

02

用户想查找某类 Agent Skill 时

03

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

04

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

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

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

能力 4

补充不同宿主或平台的使用分布数据

能力 5

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

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

平台分布

OpenClaw

81.4%
按下载量换算701

安全审计

VirusTotal

通过

ClawScan

通过

Static analysis

通过

权限和风险

需要联网

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

安装前确认

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

来源信息

继续浏览同类 Skills