NSLog

Traditional logging method available in Objective-C and Swift. Simple usage but limitations in performance and flexibility. Not recommended in modern Swift development, but may be used for maintaining compatibility with legacy code.

iOSSwiftObjective-CLoggingFoundationAppleDebug

Library

NSLog

Overview

NSLog is a traditional logging function included in Apple's Foundation framework, serving as a fundamental log output feature that has been used in iOS and macOS development for many years. It supports string formatting similar to the C printf function, automatically appending timestamps and process IDs to output to Apple System Log or Console.app. While existing since the Objective-C era and still usable in Swift, it processes synchronously causing slower performance, and Apple currently recommends migrating to OSLog.

Details

NSLog has served as a legacy API for logging on Apple platforms, functioning as a basic debugging tool for iOS/macOS developers for over 15 years. Available on all iOS and macOS versions as part of the Foundation framework, it supports message output using NSString-formatted strings. It records messages to the system log through system logging functionality, allowing log verification in Xcode's debug console and macOS Console.app. However, due to performance degradation during high-volume log output caused by synchronous processing design, Apple strongly recommends migrating to the unified logging system (OSLog/Logger) from iOS 14 onwards.

Key Features

  • Simple API: Intuitive printf-style format string output
  • Automatic Timestamps: Automatic appending of log output time and process ID
  • System Integration: Direct output to Apple System Log and Console.app
  • Cross-Language Support: Available in both Objective-C and Swift
  • Universal Compatibility: Guaranteed operation on all Apple platforms
  • Debug Support: Immediate verification in Xcode debug console

Pros and Cons

Pros

  • Easy-to-use API available immediately without learning curve
  • Compatibility across all iOS/macOS versions
  • Intuitive operation through printf-style string formatting
  • Real-time verification in Xcode debug console
  • Persistence through automatic system log integration
  • Foundation standard feature available without external dependencies

Cons

  • Clear performance issues due to synchronous processing
  • Lack of log level and category classification features
  • No privacy control or filtering functionality
  • Main thread blocking during high-volume log output
  • Limited log management features in production environments
  • Not Apple's recommended modern logging API

Reference Pages

Code Examples

Basic Setup

// Usage in Swift
import Foundation

// In Objective-C, #import <Foundation/Foundation.h> is required
// NSLog is automatically available as part of Foundation

Basic Log Output

// Basic message output
NSLog("Application started")
NSLog("Application has been initialized")

// Format strings with variables
let userName = "John Doe"
let userId = 12345
NSLog("User login: %@ (ID: %d)", userName, userId)

// Number and boolean formatting
let temperature = 23.5
let isConnected = true
NSLog("Current temperature: %.1f°C, Connection status: %@", temperature, isConnected ? "Connected" : "Disconnected")

// Complex formatting with multiple variables
let timestamp = Date()
let requestCount = 42
NSLog("Request processing completed - Time: %@, Processed: %d requests", timestamp, requestCount)
// Basic usage in Objective-C
#import <Foundation/Foundation.h>

// Basic message
NSLog(@"Application started");

// Log with variables
NSString *userName = @"John Doe";
NSInteger userId = 12345;
NSLog(@"User login: %@ (ID: %ld)", userName, (long)userId);

// Number formatting
CGFloat progress = 0.75f;
NSLog(@"Progress: %.2f%%", progress * 100);

Advanced Configuration

// Error information and stack trace output
func processData() {
    do {
        // Some processing
        let result = try performComplexOperation()
        NSLog("Data processing successful: %@", result)
    } catch {
        NSLog("Data processing error: %@", error.localizedDescription)
        NSLog("Error details: %@", error)
    }
}

// Conditional log output (debug builds only)
func debugLog(_ message: String, _ args: CVarArg...) {
    #if DEBUG
    let formattedMessage = String(format: message, args)
    NSLog("DEBUG: %@", formattedMessage)
    #endif
}

// Usage example
debugLog("Variable check: %d, %@", 42, "Test string")

// Logs with class and method information
class DataManager {
    func loadData() {
        NSLog("[%@::%@] Data loading started", NSStringFromClass(type(of: self)), #function)
        
        // Data loading process
        
        NSLog("[%@::%@] Data loading completed", NSStringFromClass(type(of: self)), #function)
    }
}

// Detailed logs with file name and line number
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)
}

// Usage example
detailedLog("Important process has been executed")

Error Handling

// Network error logging
func handleNetworkError(_ error: Error) {
    if let urlError = error as? URLError {
        switch urlError.code {
        case .notConnectedToInternet:
            NSLog("Network error: No internet connection")
        case .timedOut:
            NSLog("Network error: Timeout")
        case .cannotFindHost:
            NSLog("Network error: Cannot find host")
        default:
            NSLog("Network error: %@ (Code: %ld)", urlError.localizedDescription, urlError.errorCode)
        }
    } else {
        NSLog("Unexpected error: %@", error.localizedDescription)
    }
}

// Exception handling and logging
func safeExecute<T>(_ operation: () throws -> T) -> T? {
    do {
        let result = try operation()
        NSLog("Operation successful")
        return result
    } catch {
        NSLog("Operation failed: %@", error)
        return nil
    }
}

// Core Data error logging
func logCoreDataError(_ error: NSError) {
    NSLog("Core Data error:")
    NSLog("  Domain: %@", error.domain)
    NSLog("  Code: %ld", error.code)
    NSLog("  Description: %@", error.localizedDescription)
    
    if let userInfo = error.userInfo as? [String: Any] {
        for (key, value) in userInfo {
            NSLog("  %@: %@", key, String(describing: value))
        }
    }
}

Practical Examples

// Application lifecycle recording
class AppDelegate: UIResponder, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        NSLog("Application launch completed")
        return true
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        NSLog("Application moving to foreground")
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        NSLog("Application moving to background")
    }
}

// API request logging
class APIClient {
    func performRequest(url: String) {
        NSLog("API request started: %@", url)
        
        guard let requestURL = URL(string: url) else {
            NSLog("API request error: Invalid URL - %@", url)
            return
        }
        
        let task = URLSession.shared.dataTask(with: requestURL) { data, response, error in
            if let error = error {
                NSLog("API request failed: %@", error.localizedDescription)
                return
            }
            
            if let httpResponse = response as? HTTPURLResponse {
                NSLog("API response: Status code %ld", httpResponse.statusCode)
                
                if let data = data {
                    NSLog("API response: Data size %ld bytes", data.count)
                }
            }
        }
        
        task.resume()
    }
}

// User action recording
class UserActionLogger {
    static func logButtonTap(_ buttonTitle: String) {
        NSLog("User action: Button tap - %@", buttonTitle)
    }
    
    static func logScreenView(_ screenName: String) {
        NSLog("Screen transition: Displaying %@", screenName)
    }
    
    static func logUserEvent(_ eventName: String, parameters: [String: Any]? = nil) {
        var logMessage = "User event: \(eventName)"
        
        if let params = parameters {
            let paramStrings = params.map { "\($0.key)=\($0.value)" }
            logMessage += " [\(paramStrings.joined(separator: ", "))]"
        }
        
        NSLog("%@", logMessage)
    }
}

// Usage examples
UserActionLogger.logButtonTap("Login Button")
UserActionLogger.logScreenView("Home Screen")
UserActionLogger.logUserEvent("Product Purchase", parameters: ["Product ID": "ABC123", "Price": 1980])

// Performance measurement
class PerformanceLogger {
    private static var timers: [String: CFAbsoluteTime] = [:]
    
    static func startTimer(_ name: String) {
        timers[name] = CFAbsoluteTimeGetCurrent()
        NSLog("Performance measurement started: %@", name)
    }
    
    static func endTimer(_ name: String) {
        guard let startTime = timers.removeValue(forKey: name) else {
            NSLog("Performance measurement error: Timer '%@' not found", name)
            return
        }
        
        let duration = CFAbsoluteTimeGetCurrent() - startTime
        NSLog("Performance measurement ended: %@ - %.3f seconds", name, duration)
    }
}

// Usage example
PerformanceLogger.startTimer("Data Loading")
// Some heavy processing
PerformanceLogger.endTimer("Data Loading")