jpskill.com
🛠️ 開発・MCP コミュニティ

swift-patterns

Swiftの基本的な言語パターン(オプショナル、クロージャ、プロトコル、ジェネリクスなど)と最新機能を活用し、より効率的で保守性の高いコードを書けるように支援するSkill。

📜 元の英語説明(参考)

Core Swift language patterns, optionals, closures, protocols, generics, and modern Swift features.

🇯🇵 日本人クリエイター向け解説

一言でいうと

Swiftの基本的な言語パターン(オプショナル、クロージャ、プロトコル、ジェネリクスなど)と最新機能を活用し、より効率的で保守性の高いコードを書けるように支援するSkill。

※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。

⚡ おすすめ: コマンド1行でインストール(60秒)

下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。

🍎 Mac / 🐧 Linux
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o swift-patterns.zip https://jpskill.com/download/10681.zip && unzip -o swift-patterns.zip && rm swift-patterns.zip
🪟 Windows (PowerShell)
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/10681.zip -OutFile "$d\swift-patterns.zip"; Expand-Archive "$d\swift-patterns.zip" -DestinationPath $d -Force; ri "$d\swift-patterns.zip"

完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。

💾 手動でダウンロードしたい(コマンドが難しい人向け)
  1. 1. 下の青いボタンを押して swift-patterns.zip をダウンロード
  2. 2. ZIPファイルをダブルクリックで解凍 → swift-patterns フォルダができる
  3. 3. そのフォルダを C:\Users\あなたの名前\.claude\skills\(Win)または ~/.claude/skills/(Mac)へ移動
  4. 4. Claude Code を再起動

⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。

🎯 このSkillでできること

下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。

📦 インストール方法 (3ステップ)

  1. 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
  2. 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
  3. 3. 展開してできたフォルダを、ホームフォルダの .claude/skills/ に置く
    • · macOS / Linux: ~/.claude/skills/
    • · Windows: %USERPROFILE%\.claude\skills\

Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。

詳しい使い方ガイドを見る →
最終更新
2026-05-18
取得日時
2026-05-18
同梱ファイル
1

📖 Skill本文(日本語訳)

※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。

Swiftの言語パターン

クリーンで安全なコードのための現代的なSwiftのイディオム。

オプショナル

安全なアンラップ

// ✅ 良い例: early exitのためのguard let
func processUser(_ user: User?) {
    guard let user = user else {
        print("User is nil")
        return
    }
    // ここではuserはnon-optional
    print(user.name)
}

// ✅ 良い例: 条件付きのためのif let
if let email = user.email {
    sendEmail(to: email)
}

// ✅ 良い例: nil合体
let displayName = user.name ?? "Anonymous"

// ✅ 良い例: オプショナルチェイニング
let street = user.address?.street

// ❌ 悪い例: 強制アンラップ (nilの場合クラッシュする)
let email = user.email!  // これは避ける

オプショナルマッピング

// ✅ mapで変換
let uppercase = user.name?.map { $0.uppercased() }

// ✅ flatMapでオプショナルをチェーン
let domain = user.email?.flatMap { $0.split(separator: "@").last }

クロージャ

トレーリングクロージャ

// ✅ トレーリングクロージャ構文
viewModel.fetchUsers { users in
    self.users = users
}

// 以下と同等
viewModel.fetchUsers { users in
    self.users = users
}

// ✅ 短縮引数名
viewModel.fetchUsers {
    self.users = $0
}

キャプチャリスト

// ✅ キャプチャリストでretain cycleを回避
class UserViewController: UIViewController {
    private let viewModel: UserViewModel

    func setupRefresh() {
        viewModel.onRefresh = { [weak self] in
            guard let self = self else { return }
            self.tableView.reloadData()
        }
    }

    // ✅ オーナーシップが明確な場合はselfを明示的にキャプチャ
    func setupTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [self] _ in
            self.updateUI()
        }
    }
}

高階関数

let numbers = [1, 2, 3, 4, 5]

// ✅ map - 変換
let doubled = numbers.map { $0 * 2 }  // [2, 4, 6, 8, 10]

// ✅ filter - 選択
let evens = numbers.filter { $0 % 2 == 0 }  // [2, 4]

// ✅ reduce - 結合
let sum = numbers.reduce(0) { $0 + $1 }  // 15

// ✅ compactMap - nilを除外
let names = users.compactMap { $0.name }

// ✅ forEach - 副作用
numbers.forEach { print($0) }

// ❌ 変換にforEachを使用しない
// ❌ 悪い例: numbers.forEach { doubled.append($0 * 2) }
// ✅ 良い例: let doubled = numbers.map { $0 * 2 }

プロパティ

算出プロパティ

struct User {
    let firstName: String
    let lastName: String

    // ✅ 算出プロパティ
    var fullName: String {
        "\(firstName) \(lastName)"
    }

    // ✅ setter付き
    var age: Int {
        get { _age }
        set {
            guard newValue >= 0 else { return }
            _age = newValue
        }
    }
    private var _age: Int = 0
}

プロパティオブザーバー

class Settings {
    var theme: Theme = .light {
        didSet {
            saveSettings()
            notifyThemeChanged()
        }
    }

    var score: Int = 0 {
        willSet {
            print("Score will change from \(score) to \(newValue)")
        }
        didSet {
            if oldValue > score {
                print("Score decreased!")
            }
        }
    }
}

遅延プロパティ

struct DataProcessor {
    // ✅ 遅延 - アクセスされたときにのみ作成される
    private lazy var formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()

    func process(date: Date) -> String {
        formatter.string(from: date)
    }
}

プロトコル

プロトコル指向プログラミング

// ✅ 関連型を持つプロトコル
protocol Repository {
    associatedtype Item
    func fetch(id: String) async throws -> Item
    func save(_ item: Item) async throws
}

// ✅ ジェネリックwhere句
extension Repository {
    func fetchAll(ids: [String]) async throws -> [Item] {
        try await withThrowingTaskGroup(of: Item.self) { group in
            for id in ids {
                group.addTask { try await fetch(id: id) }
            }
            return try await group.reduce(into: [Item]()) { $0.append($1) }
        }
    }
}

プロトコルエクステンション

protocol Identifiable {
    var id: String { get }
}

extension Identifiable {
    func debugInfo() -> String {
        "ID: \(id)"
    }
}

struct User: Identifiable {
    let id: String
    let name: String
}

let user = User(id: "123", name: "John")
print(user.debugInfo())  // "ID: 123"

ジェネリクス

ジェネリック関数

// ✅ ジェネリック関数
func first<T>(_ array: [T]) -> T? {
    array.first
}

// ✅ 制約付き
func sorted<T: Comparable>(_ array: [T]) -> [T] {
    array.sorted()
}

// ✅ 複数の制約
func process<T: Sequence & Sendable>(_ items: T) where T.Element: Hashable {
    // itemsを処理
}

関連型

protocol DataSource {
    associatedtype Item
    func getItems() async throws -> [Item]
}

class RemoteDataSource: DataSource {
    typealias Item = User

    func getItems() async throws -> [User] {
        try await api.getUsers()
    }
}

Result型

// ✅ エラー処理のためのResult
func fetchUser(id: String) async -> Result<User, Error> {
    do {
        let user = try await api.getUser(id)
        return .success(user)
    } catch {
        return .failure(error)
    }
}

// 使用例
let result = await fetchUser(id: "123")
switch result {
case .success(let user):
    displayUser(user)
case .failure(let error):
    showError(error)
}

// ✅ Resultに対するmap, flatMap
let name = await fetchUser(id: "123").map(\.name)

Async/Await

構造化された並行処理


// ✅ 並行処理のためのasync let
func loadDashboard() async throws -> Dashboard {
    async let user = getUser()
    async let notifications = getNotifications()
    async let stats = getStats()

    return try await Dashboard(
        user: user,
        notifications: notifications,
        stats: stats
    )
}

// ✅ 動的な並行処理のためのTaskGroup
func fetchAllImages(urls: [URL]) async throws -> [Image] {


(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開

Swift Language Patterns

Modern Swift idioms for clean, safe code.

Optionals

Safe Unwrapping

// ✅ Good: guard let for early exit
func processUser(_ user: User?) {
    guard let user = user else {
        print("User is nil")
        return
    }
    // user is non-optional here
    print(user.name)
}

// ✅ Good: if let for conditional
if let email = user.email {
    sendEmail(to: email)
}

// ✅ Good: nil coalescing
let displayName = user.name ?? "Anonymous"

// ✅ Good: Optional chaining
let street = user.address?.street

// ❌ Bad: Force unwrap (crashes if nil)
let email = user.email!  // Don't do this

Optional Mapping

// ✅ map for transformation
let uppercase = user.name?.map { $0.uppercased() }

// ✅ flatMap for chaining optionals
let domain = user.email?.flatMap { $0.split(separator: "@").last }

Closures

Trailing Closures

// ✅ Trailing closure syntax
viewModel.fetchUsers { users in
    self.users = users
}

// Equivalent to
viewModel.fetchUsers { users in
    self.users = users
}

// ✅ Shorthand argument names
viewModel.fetchUsers {
    self.users = $0
}

Capture Lists

// ✅ Capture lists to avoid retain cycles
class UserViewController: UIViewController {
    private let viewModel: UserViewModel

    func setupRefresh() {
        viewModel.onRefresh = { [weak self] in
            guard let self = self else { return }
            self.tableView.reloadData()
        }
    }

    // ✅ Or capture self explicitly when ownership is clear
    func setupTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [self] _ in
            self.updateUI()
        }
    }
}

Higher-Order Functions

let numbers = [1, 2, 3, 4, 5]

// ✅ map - transform
let doubled = numbers.map { $0 * 2 }  // [2, 4, 6, 8, 10]

// ✅ filter - select
let evens = numbers.filter { $0 % 2 == 0 }  // [2, 4]

// ✅ reduce - combine
let sum = numbers.reduce(0) { $0 + $1 }  // 15

// ✅ compactMap - filter out nils
let names = users.compactMap { $0.name }

// ✅ forEach - side effects
numbers.forEach { print($0) }

// ❌ Don't use forEach for transformation
// ❌ Bad: numbers.forEach { doubled.append($0 * 2) }
// ✅ Good: let doubled = numbers.map { $0 * 2 }

Properties

Computed Properties

struct User {
    let firstName: String
    let lastName: String

    // ✅ Computed property
    var fullName: String {
        "\(firstName) \(lastName)"
    }

    // ✅ With setter
    var age: Int {
        get { _age }
        set {
            guard newValue >= 0 else { return }
            _age = newValue
        }
    }
    private var _age: Int = 0
}

Property Observers

class Settings {
    var theme: Theme = .light {
        didSet {
            saveSettings()
            notifyThemeChanged()
        }
    }

    var score: Int = 0 {
        willSet {
            print("Score will change from \(score) to \(newValue)")
        }
        didSet {
            if oldValue > score {
                print("Score decreased!")
            }
        }
    }
}

Lazy Properties

struct DataProcessor {
    // ✅ Lazy - created only when accessed
    private lazy var formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd"
        return formatter
    }()

    func process(date: Date) -> String {
        formatter.string(from: date)
    }
}

Protocols

Protocol-Oriented Programming

// ✅ Protocol with associated type
protocol Repository {
    associatedtype Item
    func fetch(id: String) async throws -> Item
    func save(_ item: Item) async throws
}

// ✅ Generic where clause
extension Repository {
    func fetchAll(ids: [String]) async throws -> [Item] {
        try await withThrowingTaskGroup(of: Item.self) { group in
            for id in ids {
                group.addTask { try await fetch(id: id) }
            }
            return try await group.reduce(into: [Item]()) { $0.append($1) }
        }
    }
}

Protocol Extensions

protocol Identifiable {
    var id: String { get }
}

extension Identifiable {
    func debugInfo() -> String {
        "ID: \(id)"
    }
}

struct User: Identifiable {
    let id: String
    let name: String
}

let user = User(id: "123", name: "John")
print(user.debugInfo())  // "ID: 123"

Generics

Generic Functions

// ✅ Generic function
func first<T>(_ array: [T]) -> T? {
    array.first
}

// ✅ With constraints
func sorted<T: Comparable>(_ array: [T]) -> [T] {
    array.sorted()
}

// ✅ Multiple constraints
func process<T: Sequence & Sendable>(_ items: T) where T.Element: Hashable {
    // Process items
}

Associated Types

protocol DataSource {
    associatedtype Item
    func getItems() async throws -> [Item]
}

class RemoteDataSource: DataSource {
    typealias Item = User

    func getItems() async throws -> [User] {
        try await api.getUsers()
    }
}

Result Type

// ✅ Result for error handling
func fetchUser(id: String) async -> Result<User, Error> {
    do {
        let user = try await api.getUser(id)
        return .success(user)
    } catch {
        return .failure(error)
    }
}

// Usage
let result = await fetchUser(id: "123")
switch result {
case .success(let user):
    displayUser(user)
case .failure(let error):
    showError(error)
}

// ✅ map, flatMap on Result
let name = await fetchUser(id: "123").map(\.name)

Async/Await

Structured Concurrency

// ✅ async let for concurrent work
func loadDashboard() async throws -> Dashboard {
    async let user = getUser()
    async let notifications = getNotifications()
    async let stats = getStats()

    return try await Dashboard(
        user: user,
        notifications: notifications,
        stats: stats
    )
}

// ✅ TaskGroup for dynamic concurrency
func fetchAllImages(urls: [URL]) async throws -> [Image] {
    try await withThrowingTaskGroup(of: Image.self) { group in
        for url in urls {
            group.addTask {
                try await downloadImage(from: url)
            }
        }

        var images: [Image] = []
        for try await image in group {
            images.append(image)
        }
        return images
    }
}

MainActor

// ✅ MainActor for UI updates
@MainActor
class HomeViewModel: Observable {
    @Published var users: [User] = []

    func loadUsers() async {
        // Already on main actor
        let users = try? await api.getUsers()
        self.users = users ?? []
    }
}

// ✅ Explicit main actor dispatch
class NetworkService {
    func fetch() async -> Data {
        // Background work
        let data = ...

        // Dispatch to main if needed
        await MainActor.run {
            // UI work
        }

        return data
    }
}

Enums

Associated Values

// ✅ Enum with associated values
enum NetworkError: Error {
    case invalidURL
    case noConnection
    case serverError(code: Int, message: String)
    case decodingError(Error)
}

func handle(_ error: NetworkError) {
    switch error {
    case .invalidURL:
        print("Invalid URL")
    case .noConnection:
        print("No connection")
    case .serverError(let code, let message):
        print("Server error \(code): \(message)")
    case .decodingError(let error):
        print("Decoding failed: \(error)")
    }
}

Enum as State

// ✅ Enum for exhaustive state
enum LoadState<T> {
    case idle
    case loading
    case loaded(T)
    case error(Error)

    var isLoading: Bool {
        if case .loading = self { return true }
        return false
    }

    var value: T? {
        if case .loaded(let value) = self { return value }
        return nil
    }
}

// Usage
@Published var state: LoadState<[User]> = .idle

switch state {
case .idle:
    EmptyView()
case .loading:
    ProgressView()
case .loaded(let users):
    UserList(users: users)
case .error(let error):
    ErrorView(error: error)
}

Access Control

// ✅ Use explicit access control
public struct PublicAPI {
    public var value: String

    private init() {
        value = "default"
    }

    // ✅ private for fileprivate only when needed
    private var helper: String {
        "helper"
    }

    // ✅ internal (default, same module)
    var internalValue: String = "internal"

    // ✅ fileprivate (same file)
    fileprivate var fileOnly: String = "fileOnly"
}

Key Paths

// ✅ Key paths for type-safe references
struct User {
    let name: String
    let email: String
    let age: Int
}

let nameKeyPath = \User.name
let users = [User(...)]

let names = users.map(\.name)  // [String]

// ✅ With functions
func sort<T>(_ users: [T], by keyPath: KeyPath<T, String>) -> [T] {
    users.sorted { $0[keyPath: keyPath] < $1[keyPath: keyPath] }
}

let sorted = sort(users, by: \.name)

Remember: Swift is designed for safety. Use optionals, type inference, and value types to write robust code.