はじめに
Swiftのコードを書いていると、関数の前に「class」や「static」が付くことがあります。
同じ関数に見えますが、所属するスコープや設計の意図が異なります。
基本の3種類func / class func / static func、
Swift に存在するその他の関数スタイルを個人用にまとめてます。
基本の3種類
Swiftの関数は「どのレイヤーに属するか」によって性質が変わります。
最も基本的な分類は以下の3つです。
| 種類 | 所属 | 継承 | 呼び出し方 | 主な用途 |
|---|---|---|---|---|
func |
インスタンス | ― | instance.method() |
個々のオブジェクトの動作 |
class func |
クラス | ✅ オーバーライド可 | TypeName.method() |
継承前提の共通処理 |
static func |
型(クラス/構造体/enum) | ❌ オーバーライド不可 | TypeName.method() |
固定ロジック・ユーティリティ |
1. 普通の func(インスタンスメソッド)
class User {
var name: String
init(name: String) { self.name = name }
func sayHello() {
print("Hello, my name is \(name)")
}
}
特徴
- インスタンス(オブジェクト)に紐づく関数
- クラスのプロパティや他のメソッドにアクセスできる
- 呼び出すにはインスタンスが必要
let taro = User(name: "Taro")
taro.sayHello() // → Hello, my name is Taro
メリット
- オブジェクトごとの状態を自然に扱える
- クラスの中で最も直感的に使える関数形式
デメリット
- インスタンス生成が必要
- 共通処理や定数的な関数には向かない
2. class func(クラスメソッド)
class User {
class func createGuest() -> User {
User(name: "Guest")
}
}
特徴
- クラスそのもの(型)に属する関数
- インスタンス不要で呼び出せる
- サブクラスでオーバーライド可能(final を付けることでオーバーライドを防ぐこともできます)
let guest = User.createGuest()
メリット
- 状態を持たずに共通のロジックを書ける
- サブクラスで動作を上書きできる
class Animal {
class func sound() -> String { "???" }
}
class Dog: Animal {
override class func sound() -> String { "🐶" }
}
print(Dog.sound()) // → 🐶
デメリット
- インスタンスの状態に直接アクセスできない
- 設計図的・抽象的な処理向け
3. static func(静的メソッド)
struct Math {
static func square(_ n: Int) -> Int {
n * n
}
}
特徴
- 型に属するが、継承もオーバーライドもできない
- 構造体や enum にも使える
- 完全に固定された共通ロジック
Math.square(4) // → 16
メリット
- 処理が安定しており安全(変更されない)
- ユーティリティ・定数ロジックに最適
デメリット
- 継承設計が必要な場合は柔軟性がない
ドキュメント貼っときます。
例:QuickSpec での class func の応用例
Quick ではテスト構造を定義するために spec() メソッドをオーバーライドします。
final class MySpec: QuickSpec {
override class func spec() {
describe("Example") {
it("works") { ... }
}
}
}
class func の大きなメリット
Quick はこの spec() を各クラスで1回だけ呼び出し、
「どんなテストがあるか」を登録します。
ここで static func にしてしまうと上書きできないため、
各テストクラスが自分の構成を定義できなくなります。
だからこそ、spec() は class func で宣言されています。
所謂Factory パターンもclass funcを使うと思います。
さらに広げる:その他の関数の種類
ここまでは「型の中の関数」でしたが、
Swiftにはそれ以外にも用途やコンテキストで異なる関数の形があります。
① グローバル関数
クラスや構造体に属さない、完全に自由な関数。
func sayHello() {
print("Hello")
}
標準ライブラリの print() など。
どの型にも属さない汎用的な処理に使う。
② Extension内の関数
既存の型に新しいメソッドを“後付け”できます。
extension String {
func shout() -> String {
self.uppercased() + "!"
}
}
"hello".shout() // → "HELLO!"
コードの責務を分けたり、外部ライブラリを拡張したいときに便利。
③ Protocol内の関数
プロトコルで定義された関数。
protocol Greeter {
func greet()
}
この関数は「契約」なので、
採用したクラスや構造体は必ず greet() を実装しなければなりません。
→ DI(依存性注入)やモック化にも必須の要素。
④ Actor内の関数(Swift Concurrency)
Swift Concurrency で導入された「アクター」は、
並行処理におけるデータ競合を防ぐ仕組み。
actor Logger {
func write(_ text: String) {
print("[LOG] \(text)")
}
}
呼び出す側は await を付ける必要があります。
ただすべてのactor内の関数が await 必須というわけではなく、同じactor内からの呼び出しでは不要。
await logger.write("started")
→ 自動的にスレッドセーフなメソッドになる。
⑤ @MainActor func
UIスレッド(メインスレッド)で必ず実行したい関数。
@MainActor
func updateUI() {
label.text = "Updated"
}
UIKit や SwiftUI のような UI更新処理ではこれが基本。
⑥ nonisolated func
アクターの中にあるけれど、あえてアクターの外から直接呼べる関数。
actor DataManager {
nonisolated func version() -> String { "1.0.0" }
}
-
awaitなしで呼べる - アクターの分離から除外されているため、アクターの状態にアクセスできない。読み取り専用処理に向く
Swiftの関数マップ
| 種類 | 所属 | 継承 | 主な用途 | 特徴 |
|---|---|---|---|---|
func |
インスタンス | ― | 個々の動作 | 状態を扱う・最も一般的 |
class func |
クラス | ✅ 可能 | 継承前提の共通処理 | 設計図としての動作 |
static func |
型(クラス/構造体/enum) | ❌ 不可 | 固定ロジック | 軽量で安全 |
| Free Function | グローバル | ― | 共通処理 | 型に属さない |
| Extension func | 任意の型 | ― | 機能追加 | 責務分割に便利 |
| Protocol func | プロトコル | 実装義務あり | 契約・抽象化 | テスト・DI向け |
| Actor func | アクター | ― | 並行処理安全 | 自動でデータ競合なし |
| @MainActor func | アクター(UI専用) | ― | メインスレッド | UI更新向け |
| nonisolated func | アクター内 | ― | 軽量読み取り | 並行安全外で動作 |
まとめ
-
func→ オブジェクトがどう動くか -
class func→ 型がどう動くか -
static func→ 絶対に変わらないルール - そのほか → 並行処理、安全性、抽象化などの文脈に応じた拡張形
この違いを意識して使い分けられるようになると、
コードの責務が明確になる印象。