NSLog

Objective-CとSwiftで利用可能な伝統的なロギングメソッド。シンプルな使用方法だが、パフォーマンスと柔軟性の面で制限あり。現代のSwift開発では推奨されないが、レガシーコードとの互換性維持で使用される場合がある。

ロギングiOSmacOSObjective-CSwiftAppleデバッグコンソール

ライブラリ

NSLog

概要

NSLogは、Apple のFoundationフレームワークに含まれる伝統的なロギング関数で、iOS、macOS開発において長年使用されてきた基本的なログ出力機能です。C言語のprintf関数に似た形式で文字列フォーマットをサポートし、タイムスタンプとプロセスIDを自動的に付与してApple System LogまたはConsole.appに出力。Objective-Cの時代から存在し、Swiftでも使用可能ですが、同期処理のため処理速度が遅く、Apple は現在OSLogへの移行を推奨しています。

詳細

NSLogは、AppleプラットフォームでのロギングにおけるレガシーAPIとして、15年以上にわたってiOS/macOS開発者の基本的なデバッグツールとして利用されてきました。Foundation フレームワークの一部として全てのiOS、macOSバージョンで利用可能で、NSString形式の文字列フォーマットを用いたメッセージ出力をサポートします。システムログ機能を通じてデバイスのコンソールログにメッセージを記録し、XcodeのデバッグコンソールやmacOSのConsole.appでログを確認できます。ただし、同期的な処理設計により大量のログ出力時にパフォーマンスが低下する可能性があり、AppleはiOS 14以降、統合ログシステム(OSLog/Logger)への移行を強く推奨しています。

主な特徴

  • シンプルなAPI: printf風の直感的なフォーマット文字列による出力
  • 自動タイムスタンプ: ログ出力時刻とプロセスIDの自動付与
  • システム統合: Apple System LogとConsole.appへの直接出力
  • 言語横断対応: Objective-CとSwiftの両方での利用可能
  • ユニバーサル対応: すべてのAppleプラットフォームで動作保証
  • デバッグサポート: Xcodeデバッグコンソールでの即座な確認

メリット・デメリット

メリット

  • 学習コストなしで即座に使用可能な簡単なAPI
  • すべてのiOS/macOSバージョンで利用可能な互換性
  • printf風の文字列フォーマットによる直感的な操作
  • Xcodeデバッグコンソールでのリアルタイム確認
  • システムログとの自動統合による永続化
  • 外部依存なしで利用可能なFoundation標準機能

デメリット

  • 同期処理による明確なパフォーマンス問題
  • ログレベルやカテゴリ分類機能の欠如
  • プライバシー制御やフィルタリング機能なし
  • 大量ログ出力時のメインスレッドブロック
  • 本番環境でのログ管理機能が限定的
  • Apple推奨の現代的ログAPIではない

参考ページ

書き方の例

基本セットアップ

// Swift での使用
import Foundation

// Objective-C では #import <Foundation/Foundation.h> が必要
// NSLog は Foundation の一部として自動的に利用可能

基本的なログ出力

// 基本的なメッセージ出力
NSLog("アプリケーションが開始されました")
NSLog("Application started")

// 変数を含むフォーマット文字列
let userName = "田中太郎"
let userId = 12345
NSLog("ユーザーログイン: %@ (ID: %d)", userName, userId)

// 数値とブール値のフォーマット
let temperature = 23.5
let isConnected = true
NSLog("現在の温度: %.1f°C, 接続状態: %@", temperature, isConnected ? "接続" : "切断")

// 複数の変数を含む複雑なフォーマット
let timestamp = Date()
let requestCount = 42
NSLog("リクエスト処理完了 - 時刻: %@, 処理件数: %d件", timestamp, requestCount)
// Objective-C での基本的な使用例
#import <Foundation/Foundation.h>

// 基本メッセージ
NSLog(@"アプリケーションが開始されました");

// 変数を含むログ
NSString *userName = @"田中太郎";
NSInteger userId = 12345;
NSLog(@"ユーザーログイン: %@ (ID: %ld)", userName, (long)userId);

// 数値フォーマット
CGFloat progress = 0.75f;
NSLog(@"進捗: %.2f%%", progress * 100);

高度な設定

// エラー情報とスタックトレースの出力
func processData() {
    do {
        // 何らかの処理
        let result = try performComplexOperation()
        NSLog("データ処理成功: %@", result)
    } catch {
        NSLog("データ処理エラー: %@", error.localizedDescription)
        NSLog("エラー詳細: %@", error)
    }
}

// 条件付きログ出力(デバッグビルドのみ)
func debugLog(_ message: String, _ args: CVarArg...) {
    #if DEBUG
    let formattedMessage = String(format: message, args)
    NSLog("DEBUG: %@", formattedMessage)
    #endif
}

// 使用例
debugLog("変数値確認: %d, %@", 42, "テスト文字列")

// クラスとメソッド情報を含むログ
class DataManager {
    func loadData() {
        NSLog("[%@::%@] データ読み込み開始", NSStringFromClass(type(of: self)), #function)
        
        // データ読み込み処理
        
        NSLog("[%@::%@] データ読み込み完了", NSStringFromClass(type(of: self)), #function)
    }
}

// ファイル名と行番号を含む詳細ログ
func detailedLog(_ message: String, file: String = #file, line: Int = #line, function: String = #function) {
    let fileName = (file as NSString).lastPathComponent
    NSLog("[%@:%d %@] %@", fileName, line, function, message)
}

// 使用例
detailedLog("重要な処理が実行されました")

エラーハンドリング

// ネットワークエラーのログ記録
func handleNetworkError(_ error: Error) {
    if let urlError = error as? URLError {
        switch urlError.code {
        case .notConnectedToInternet:
            NSLog("ネットワークエラー: インターネット接続なし")
        case .timedOut:
            NSLog("ネットワークエラー: タイムアウト")
        case .cannotFindHost:
            NSLog("ネットワークエラー: ホストが見つかりません")
        default:
            NSLog("ネットワークエラー: %@ (コード: %ld)", urlError.localizedDescription, urlError.errorCode)
        }
    } else {
        NSLog("予期しないエラー: %@", error.localizedDescription)
    }
}

// 例外処理とログ記録
func safeExecute<T>(_ operation: () throws -> T) -> T? {
    do {
        let result = try operation()
        NSLog("操作成功")
        return result
    } catch {
        NSLog("操作失敗: %@", error)
        return nil
    }
}

// Core Data エラーのログ記録
func logCoreDataError(_ error: NSError) {
    NSLog("Core Data エラー:")
    NSLog("  ドメイン: %@", error.domain)
    NSLog("  コード: %ld", error.code)
    NSLog("  説明: %@", error.localizedDescription)
    
    if let userInfo = error.userInfo as? [String: Any] {
        for (key, value) in userInfo {
            NSLog("  %@: %@", key, String(describing: value))
        }
    }
}

実用例

// アプリケーションライフサイクルの記録
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        NSLog("アプリケーション起動完了")
        return true
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        NSLog("アプリケーションがフォアグラウンドに移行")
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        NSLog("アプリケーションがバックグラウンドに移行")
    }
}

// APIリクエストのログ記録
class APIClient {
    func performRequest(url: String) {
        NSLog("API リクエスト開始: %@", url)
        
        guard let requestURL = URL(string: url) else {
            NSLog("API リクエストエラー: 無効なURL - %@", url)
            return
        }
        
        let task = URLSession.shared.dataTask(with: requestURL) { data, response, error in
            if let error = error {
                NSLog("API リクエスト失敗: %@", error.localizedDescription)
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                NSLog("API レスポンス: ステータスコード %ld", httpResponse.statusCode)
                
                if let data = data {
                    NSLog("API レスポンス: データサイズ %ld bytes", data.count)
                }
            }
        }
        
        task.resume()
    }
}

// ユーザーアクションの記録
class UserActionLogger {
    static func logButtonTap(_ buttonTitle: String) {
        NSLog("ユーザーアクション: ボタンタップ - %@", buttonTitle)
    }
    
    static func logScreenView(_ screenName: String) {
        NSLog("画面遷移: %@ を表示", screenName)
    }
    
    static func logUserEvent(_ eventName: String, parameters: [String: Any]? = nil) {
        var logMessage = "ユーザーイベント: \(eventName)"
        
        if let params = parameters {
            let paramStrings = params.map { "\($0.key)=\($0.value)" }
            logMessage += " [\(paramStrings.joined(separator: ", "))]"
        }
        
        NSLog("%@", logMessage)
    }
}

// 使用例
UserActionLogger.logButtonTap("ログインボタン")
UserActionLogger.logScreenView("ホーム画面")
UserActionLogger.logUserEvent("商品購入", parameters: ["商品ID": "ABC123", "価格": 1980])

// パフォーマンス測定
class PerformanceLogger {
    private static var timers: [String: CFAbsoluteTime] = [:]
    
    static func startTimer(_ name: String) {
        timers[name] = CFAbsoluteTimeGetCurrent()
        NSLog("パフォーマンス測定開始: %@", name)
    }
    
    static func endTimer(_ name: String) {
        guard let startTime = timers.removeValue(forKey: name) else {
            NSLog("パフォーマンス測定エラー: タイマー '%@' が見つかりません", name)
            return
        }
        
        let duration = CFAbsoluteTimeGetCurrent() - startTime
        NSLog("パフォーマンス測定終了: %@ - %.3f秒", name, duration)
    }
}

// 使用例
PerformanceLogger.startTimer("データ読み込み")
// 何らかの重い処理
PerformanceLogger.endTimer("データ読み込み")