Xcodeでコードを書いていると、ファイルが長くなって「あの関数どこだっけ?」と探すのに時間がかかることはありませんか?また、「後で実装しよう」と思ったことを忘れてしまった経験はないでしょうか。
実は、Xcodeには特殊なコメントマークを使って、コードを整理したりタスクを管理したりする便利な機能があります。この記事では、MARK、TODO、FIXMEをはじめとする、Xcodeで使える全てのコメントマークを初心者の方にもわかりやすく解説します。
Xcodeのコメントマークとは?
Xcodeのコメントマークは、特定のキーワードを含むコメントを書くことで、コードの整理やタスク管理を助けてくれる機能です。
通常のコメントと同じように//
で書きますが、特定のキーワード(MARK、TODO、FIXMEなど)を使うことで、Xcodeのジャンプバーに表示されたり、検索しやすくなったりします。
ジャンプバーとは?
ジャンプバーは、Xcodeのエディタ上部にある「現在編集している関数名やクラス名」が表示される部分です。この部分をクリックすると、ファイル内の構造やコメントマークが一覧表示され、すぐにジャンプできます。
Xcodeで使える6つのコメントマーク
それでは、Xcodeで使える主要なコメントマークを1つずつ見ていきましょう。
1. MARK: – コードのセクション分け
MARK:
は、コードをセクションに分けて整理するためのマークです。大きなファイルを論理的なブロックに分割できます。
// MARK: - Properties
private var userName: String = ""
private var userAge: Int = 0
// MARK: - Initializer
init(name: String, age: Int) {
self.userName = name
self.userAge = age
}
// MARK: - Public Methods
func greet() {
print("Hello, \(userName)!")
}
// MARK: - Private Methods
private func calculateAge() {
// 処理
}
ポイント:
MARK:
の後にハイフン-
を付けると、ジャンプバーで区切り線が表示される- セクション名は自由に決められる
- よく使われるセクション名:Properties、Initializer、Lifecycle、Setup、Actions、Public Methods、Private Methods
ジャンプバーでの表示:
MyClass
├─ Properties
├─ Initializer
├─ Public Methods
└─ Private Methods
2. TODO: – やるべきタスクの記録
TODO:
は、後で実装する予定の機能や、やり残しているタスクを記録するマークです。
func loginUser(email: String, password: String) {
// TODO: バリデーション処理を追加
// TODO: パスワードの暗号化を実装
// TODO: エラーハンドリングを追加
// 仮の実装
print("Login attempt")
}
使用場面:
- 機能の未実装部分
- 後回しにする改善点
- まだ書いていないテストケース
具体例:
class ShoppingCartViewController: UIViewController {
// TODO: Core Dataとの連携を実装
private var cartItems: [Item] = []
override func viewDidLoad() {
super.viewDidLoad()
// TODO: 空のカート時のUIを実装
setupTableView()
}
@IBAction func checkoutButtonTapped(_ sender: UIButton) {
// TODO: 決済処理を実装
showAlert(message: "準備中です")
}
}
3. FIXME: – 修正が必要なバグ
FIXME:
は、既知のバグや修正が必要な問題箇所を示すマークです。TODOよりも緊急度が高い問題に使います。
func calculateTotal(items: [Item]) -> Double {
var total = 0.0
for item in items {
// FIXME: 消費税の計算が間違っている
total += item.price * 1.08
}
return total
}
func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
// FIXME: タイムゾーンが考慮されていない
formatter.dateFormat = "yyyy/MM/dd"
return formatter.string(from: date)
}
TODOとFIXMEの使い分け:
- TODO: 新しい機能の追加や改善(緊急度:低〜中)
- FIXME: 既存のコードのバグや問題(緊急度:高)
4. WARNING: / !!!: – 重要な警告
WARNING:
または!!!:
は、コードを使う際の注意事項や警告を示すマークです。
class NetworkManager {
// WARNING: このクラスはシングルトンとして使用すること
static let shared = NetworkManager()
private init() {}
func fetchData(completion: @escaping (Data?) -> Void) {
// !!!: この処理は時間がかかる可能性があります
// メインスレッドで呼び出さないこと
URLSession.shared.dataTask(with: url) { data, _, _ in
completion(data)
}.resume()
}
}
// WARNING: 非推奨のAPIです。NewAPIを使用してください
@available(*, deprecated, message: "Use NewAPI instead")
func oldFunction() {
// 処理
}
使用場面:
- パフォーマンスに影響する処理
- スレッドセーフティの注意
- 非推奨のコードや関数
- セキュリティ上の注意点
5. NOTE: – 重要な補足情報
NOTE:
は、コードの動作に関する重要な補足情報を記載するマークです。
class ImageProcessor {
func processImage(_ image: UIImage) -> UIImage {
// NOTE: この処理はメモリを多く消費するため、
// バックグラウンドスレッドで実行することを推奨
let processedImage = applyFilters(to: image)
return processedImage
}
private func saveToCache(_ image: UIImage, key: String) {
// NOTE: キャッシュは24時間で自動削除されます
cache.setObject(image, forKey: key as NSString)
}
}
// NOTE: このViewControllerはStoryboardからのみ初期化可能
class ProfileViewController: UIViewController {
@IBOutlet weak var nameLabel: UILabel!
}
使用場面:
- 前提条件や制約
- 仕様に関する重要な情報
- 他の開発者への引き継ぎ事項
6. HACK: – 一時的な回避策
HACK:
は、理想的ではないが動作する一時的な解決策を示すマークです。技術的負債として後で改善が必要なコードに使います。
func loadUserData() {
// HACK: APIのバグのため、2回リクエストを送る必要がある
// 本来は1回で取得できるべき
fetchUserProfile { profile in
self.fetchUserSettings { settings in
self.updateUI(profile: profile, settings: settings)
}
}
}
class CustomButton: UIButton {
override func layoutSubviews() {
super.layoutSubviews()
// HACK: Auto Layoutの不具合の回避策
// iOS 15.0以降では不要になる予定
DispatchQueue.main.async {
self.layer.cornerRadius = self.bounds.height / 2
}
}
}
使用場面:
- サードパーティライブラリのバグ回避
- OSのバグの一時的な対応
- パフォーマンスのための妥協案
- リファクタリング予定のコード
実践的な使用例:ViewControllerの整理
実際のプロジェクトでこれらのマークをどう使うか、具体例を見てみましょう。
import UIKit
// MARK: - LoginViewController
class LoginViewController: UIViewController {
// MARK: - Properties
// NOTE: これらのOutletはStoryboardから接続されています
@IBOutlet weak var emailTextField: UITextField!
@IBOutlet weak var passwordTextField: UITextField!
@IBOutlet weak var loginButton: UIButton!
private var isLoading = false {
didSet {
updateLoadingState()
}
}
// TODO: ログイン状態を保持する仕組みを実装
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupUI()
setupKeyboardHandling()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// FIXME: キーボードが表示されたままになる問題を修正
emailTextField.becomeFirstResponder()
}
// MARK: - Setup
private func setupUI() {
loginButton.layer.cornerRadius = 8
loginButton.backgroundColor = .systemBlue
}
private func setupKeyboardHandling() {
// WARNING: キーボード通知の登録を忘れずに解除すること
NotificationCenter.default.addObserver(
self,
selector: #selector(keyboardWillShow),
name: UIResponder.keyboardWillShowNotification,
object: nil
)
}
// MARK: - Actions
@IBAction func loginButtonTapped(_ sender: UIButton) {
guard validateInputs() else {
showValidationError()
return
}
performLogin()
}
@IBAction func forgotPasswordTapped(_ sender: UIButton) {
// TODO: パスワードリセット画面への遷移を実装
print("パスワードをお忘れですか?")
}
// MARK: - Validation
private func validateInputs() -> Bool {
// TODO: より厳密なバリデーションを追加
// - メールアドレスの形式チェック
// - パスワードの最小文字数チェック
guard let email = emailTextField.text, !email.isEmpty else {
return false
}
guard let password = passwordTextField.text, !password.isEmpty else {
return false
}
return true
}
// MARK: - Network
private func performLogin() {
isLoading = true
let email = emailTextField.text ?? ""
let password = passwordTextField.text ?? ""
// HACK: 本来はAPIクライアントを経由すべきだが、
// 現状は直接URLSessionを使用
let url = URL(string: "https://api.example.com/login")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// !!!: パスワードは暗号化してから送信すること
let body = ["email": email, "password": password]
request.httpBody = try? JSONSerialization.data(withJSONObject: body)
URLSession.shared.dataTask(with: request) { [weak self] data, response, error in
DispatchQueue.main.async {
self?.isLoading = false
if let error = error {
// FIXME: エラーハンドリングが不十分
print("Error: \(error)")
return
}
self?.handleLoginSuccess()
}
}.resume()
}
// MARK: - UI Updates
private func updateLoadingState() {
loginButton.isEnabled = !isLoading
loginButton.setTitle(isLoading ? "ログイン中..." : "ログイン", for: .normal)
}
private func handleLoginSuccess() {
// TODO: ホーム画面への遷移を実装
print("ログイン成功")
}
private func showValidationError() {
let alert = UIAlertController(
title: "エラー",
message: "メールアドレスとパスワードを入力してください",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "OK", style: .default))
present(alert, animated: true)
}
// MARK: - Keyboard Handling
@objc private func keyboardWillShow(_ notification: Notification) {
// NOTE: キーボードの高さに応じてビューを調整
guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
return
}
let keyboardHeight = keyboardFrame.height
// 処理
}
// MARK: - Deinit
deinit {
// NOTE: 通知の登録を解除
NotificationCenter.default.removeObserver(self)
}
}
この例では、6つのコメントマークを適切に使い分けることで、コードの構造が明確になり、タスクや問題点も一目でわかるようになっています。
ジャンプバーでの活用方法
コメントマークを設定したら、ジャンプバーから素早くアクセスできます。
ジャンプバーの使い方
- エディタ上部のジャンプバー(現在のクラス名・関数名が表示されている部分)をクリック
- ファイルの構造とコメントマークが階層的に表示される
- 移動したい項目をクリックすると、その場所にジャンプ
ジャンプバーでの表示例
LoginViewController
├─ Properties
│ └─ emailTextField
│ └─ passwordTextField
│ └─ isLoading
├─ Lifecycle
│ └─ viewDidLoad()
│ └─ viewWillAppear(_:)
├─ Setup
│ └─ setupUI()
│ └─ setupKeyboardHandling()
├─ Actions
│ └─ loginButtonTapped(_:)
│ └─ forgotPasswordTapped(_:)
├─ Validation
├─ Network
├─ UI Updates
├─ Keyboard Handling
└─ Deinit
コメントマークを検索する方法
プロジェクト全体のTODOやFIXMEを一覧表示する方法を紹介します。
方法1: Xcodeの検索機能を使う
⌘ + Shift + F
(プロジェクト内検索)を開く- 検索ボックスに「TODO」「FIXME」などと入力
- プロジェクト全体のマークが一覧表示される
方法2: Show Document Items(推奨)
- エディタでファイルを開く
Control + 6
を押す- ファイル内の全てのマークと関数が表示される
- 検索ボックスでフィルタリング可能
方法3: Find Navigatorを使う
- 左サイドバーの虫眼鏡アイコンをクリック
- 「Text」を選択して「TODO」「FIXME」で検索
- プロジェクト全体の該当箇所が表示される
コメントマークのベストプラクティス
効果的にコメントマークを使うためのポイントをまとめます。
1. 一貫性を保つ
チーム内で統一されたルールを決めましょう。
// ✅ 良い例:チーム全体で統一された書き方
// MARK: - Properties
// TODO: 認証機能を追加
// FIXME: メモリリークを修正
// ❌ 悪い例:バラバラな書き方
//MARK:Properties
// Todo: 認証機能を追加
//fixme メモリリークを修正
2. 具体的に書く
何をすべきか明確にしましょう。
// ✅ 良い例:具体的な内容
// TODO: UserDefaultsにログイン状態を保存する処理を追加
// FIXME: iOS 14以降で発生するクラッシュを修正(Issue #123参照)
// ❌ 悪い例:曖昧な内容
// TODO: 修正
// FIXME: バグ
3. 優先順位を明確にする
緊急度に応じて使い分けます。
緊急度 高: FIXME(バグや重大な問題)
緊急度 中: TODO(必要な機能追加)
緊急度 低: NOTE、HACK(情報共有や将来的な改善)
4. 期限や担当者を書く
チーム開発では特に有効です。
// TODO: [田中] v2.0リリースまでにプッシュ通知機能を実装
// FIXME: [佐藤] 2024/12/31までに修正(本番環境で発生中)
5. 解決したら削除する
コメントマークは一時的なものです。問題が解決したら削除しましょう。
6. MARKは大きな単位で使う
細かすぎる分割は逆に見づらくなります。
// ✅ 良い例:適切な粒度
// MARK: - Properties
// MARK: - Lifecycle
// MARK: - Public Methods
// MARK: - Private Methods
// ❌ 悪い例:細かすぎる
// MARK: - プロパティ1
// MARK: - プロパティ2
// MARK: - プロパティ3
チーム開発での活用テクニック
コードレビューでの活用
// TODO: [レビュー待ち] この実装で問題ないか確認してください
func complexCalculation() -> Double {
// 複雑な計算処理
}
イシュー番号との連携
// FIXME: Issue #456 - ログイン後にクラッシュする問題
// TODO: Issue #789 - ダークモード対応
バージョン情報の記載
// TODO: v2.0で実装予定
// FIXME: v1.5で削除予定(非推奨API使用中)
まとめ
この記事では、Xcodeで使える6つのコメントマークを解説しました。
コメントマークの使い分け:
- MARK: コードのセクション分け
- TODO: 未実装の機能や改善点
- FIXME: 既知のバグや修正箇所
- WARNING/!!!: 重要な警告や注意事項
- NOTE: 補足情報や仕様の説明
- HACK: 一時的な回避策
活用のポイント:
- ジャンプバーで素早くナビゲーション
- 検索機能でタスク管理
- チーム内で統一したルールを決める
- 具体的で明確な内容を書く
- 解決したら削除する
これらのコメントマークを効果的に使うことで、コードの可読性が向上し、タスク管理もスムーズになります。特に大規模なプロジェクトやチーム開発では、威力を発揮する機能です。