🎯 Ejemplos recomendados
Balanced sample collections from various categories for you to explore
Ejemplos de Manejo de Errores macOS Swift
Ejemplos de manejo de errores macOS Swift incluyendo captura de excepciones, registro y validación de parámetros
💻 Captura de Excepciones swift
🟢 simple
⭐⭐
Manejar errores usando bloques do-catch, patrones try-catch y tipos de error personalizados
⏱️ 25 min
🏷️ swift, macos, error
Prerequisites:
Basic Swift, Error types
// macOS Swift Exception Catching Examples
// Error handling with do-catch, throws, and custom errors
import Foundation
// 1. Define Custom Error Types
enum NetworkError: Error, LocalizedError {
case invalidURL
case connectionFailed
case timeout
case serverError(code: Int)
var errorDescription: String? {
switch self {
case .invalidURL:
return "The provided URL is invalid"
case .connectionFailed:
return "Failed to establish network connection"
case .timeout:
return "Request timed out"
case .serverError(let code):
return "Server returned error code: \(code)"
}
}
}
enum ValidationError: Error {
case emptyInput
case invalidFormat
case outOfRange(min: Int, max: Int, value: Int)
case tooShort(length: Int, minLength: Int)
var localizedDescription: String {
switch self {
case .emptyInput:
return "Input cannot be empty"
case .invalidFormat:
return "Input format is invalid"
case .outOfRange(let min, let max, let value):
return "Value \(value) is out of range [\(min), \(max)]"
case .tooShort(let length, let minLength):
return "Input length \(length) is too short (minimum: \(minLength))"
}
}
}
// 2. Basic do-catch Error Handling
class BasicErrorHandling {
func divide(_ a: Int, by b: Int) throws -> Double {
guard b != 0 else {
throw NSError(domain: "MathError", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Division by zero is not allowed"
])
}
return Double(a) / Double(b)
}
func demonstrateBasicCatch() {
print("\n--- Basic do-catch Error Handling ---")
do {
let result = try divide(10, by: 2)
print("10 / 2 = \(result)")
} catch {
print("Error: \(error.localizedDescription)")
}
// Error case
do {
let result = try divide(10, by: 0)
print("Result: \(result)")
} catch {
print("Caught error: \(error.localizedDescription)")
}
}
}
// 3. Multiple Catch Blocks
class MultipleCatchBlocks {
func processOperation(value: Int) throws -> String {
if value < 0 {
throw NetworkError.invalidURL
} else if value == 0 {
throw ValidationError.emptyInput
}
return "Success: \(value)"
}
func demonstrateMultipleCatches() {
print("\n--- Multiple Catch Blocks ---")
let values = [-1, 0, 5]
for value in values {
do {
let result = try processOperation(value: value)
print(result)
} catch let error as NetworkError {
print("Network error: \(error.errorDescription ?? "Unknown")")
} catch let error as ValidationError {
print("Validation error: \(error.localizedDescription)")
} catch {
print("Generic error: \(error.localizedDescription)")
}
}
}
}
// 4. try? - Convert to Optional
class OptionalTry {
func riskyOperation(success: Bool) throws -> String {
if success {
return "Operation succeeded"
} else {
throw NSError(domain: "Error", code: 1)
}
}
func demonstrateOptionalTry() {
print("\n--- try? - Convert to Optional ---")
// Success case - returns Optional("Operation succeeded")
let result1 = try? riskyOperation(success: true)
print("Result 1: \(result1 ?? "nil")")
// Failure case - returns nil instead of throwing
let result2 = try? riskyOperation(success: false)
print("Result 2: \(result2?.description ?? "nil")")
// Chaining with nil coalescing
let finalResult = (try? riskyOperation(success: false)) ?? "Default value"
print("Final result: \(finalResult)")
}
}
// 5. try! - Force Unwrap
class ForceTry {
func forceUnwrapDemo() {
print("\n--- try! - Force Unwrap ---")
// This works because operation succeeds
let result1 = try! riskyOperation(success: true)
print("Force unwrap success: \(result1)")
// This would crash because operation fails
do {
// let result2 = try! riskyOperation(success: false) // CRASH!
// print("Never reached")
}
print("Use try! only when you're certain the operation won't fail")
}
private func riskyOperation(success: Bool) throws -> String {
return success ? "Success" : "Failure"
}
}
// 6. defer Statement
class DeferExample {
func processFile(path: String) throws -> String {
print("\n--- Defer Statement ---")
print("Opening file: \(path)")
// defer will execute when scope exits
defer {
print("Closing file: \(path)")
}
// Simulate processing
print("Processing file...")
if path.isEmpty {
throw ValidationError.emptyInput
}
return "File processed successfully"
}
func demonstrateDefer() {
do {
let result = try processFile(path: "/path/to/file.txt")
print(result)
} catch {
print("Error: \(error)")
}
// Error case - defer still executes
do {
let result = try processFile(path: "")
print(result)
} catch {
print("Error caught: \(error)")
}
}
// Multiple defer blocks (LIFO order)
func multipleDefer() {
print("\n--- Multiple Defer Blocks ---")
defer { print("Defer 1") }
defer { print("Defer 2") }
defer { print("Defer 3") }
print("Main code")
}
}
// 7. Rethrowing Functions
class RethrowingExample {
func transform<T>(_ value: T, using transform: (T) throws -> String) rethrows -> String {
print("\n--- Rethrowing Function ---")
return try transform(value)
}
func demonstrateRethrow() {
do {
let result = try transform(42) { value in
if value < 0 {
throw ValidationError.invalidFormat
}
return "Transformed: \(value)"
}
print(result)
} catch {
print("Error: \(error)")
}
}
}
// 8. Error Propagation
class ErrorPropagation {
func step1() throws -> String {
print("Step 1")
return "Step1"
}
func step2(input: String) throws -> String {
print("Step 2 with: \(input)")
if input.isEmpty {
throw ValidationError.emptyInput
}
return input + " -> Step2"
}
func step3(input: String) throws -> String {
print("Step 3 with: \(input)")
return input + " -> Step3"
}
func executePipeline() throws -> String {
print("\n--- Error Propagation ---")
let result1 = try step1()
let result2 = try step2(input: result1)
let result3 = try step3(input: result2)
return result3
}
func demonstratePropagation() {
do {
let result = try executePipeline()
print("Pipeline result: \(result)")
} catch {
print("Pipeline failed: \(error)")
}
}
}
// 9. Result Type for Error Handling
class ResultTypeExample {
func divideResult(_ a: Int, by b: Int) -> Result<Double, Error> {
guard b != 0 else {
return .failure(NSError(domain: "MathError", code: 1, userInfo: [
NSLocalizedDescriptionKey: "Division by zero"
]))
}
return .success(Double(a) / Double(b))
}
func demonstrateResult() {
print("\n--- Result Type ---")
let result1 = divideResult(10, by: 2)
switch result1 {
case .success(let value):
print("10 / 2 = \(value)")
case .failure(let error):
print("Error: \(error)")
}
// Error case
let result2 = divideResult(10, by: 0)
switch result2 {
case .success(let value):
print("Result: \(value)")
case .failure(let error):
print("Error: \(error.localizedDescription)")
}
// Using get() method
if let value = try? divideResult(20, by: 4).get() {
print("Direct get: \(value)")
}
}
}
// 10. Comprehensive Error Handler
class ComprehensiveErrorHandler {
enum AppError: Error {
case network(NetworkError)
case validation(ValidationError)
case unknown(Error)
var localizedDescription: String {
switch self {
case .network(let error):
return "Network: \(error.errorDescription ?? "Unknown")"
case .validation(let error):
return "Validation: \(error.localizedDescription)"
case .unknown(let error):
return "Unknown: \(error.localizedDescription)"
}
}
}
func handleOperation(operation: () throws -> Void) {
print("\n--- Comprehensive Error Handling ---")
do {
try operation()
print("Operation completed successfully")
} catch let error as NetworkError {
let appError = AppError.network(error)
handleAppError(appError)
} catch let error as ValidationError {
let appError = AppError.validation(error)
handleAppError(appError)
} catch {
let appError = AppError.unknown(error)
handleAppError(appError)
}
}
private func handleAppError(_ error: AppError) {
print("Error occurred: \(error.localizedDescription)")
switch error {
case .network:
print("Suggested action: Check your internet connection")
case .validation:
print("Suggested action: Please check your input")
case .unknown:
print("Suggested action: Please try again later")
}
}
func demonstrateComprehensive() {
// Success case
handleOperation {
print("Executing operation...")
}
// Network error
handleOperation {
throw NetworkError.connectionFailed
}
// Validation error
handleOperation {
throw ValidationError.invalidFormat
}
}
}
// 11. Async Error Handling
class AsyncErrorHandling {
func fetchData() async throws -> String {
print("\n--- Async Error Handling ---")
// Simulate async operation
try await Task.sleep(nanoseconds: 100_000_000) // 0.1 seconds
let success = true
if success {
return "Data fetched successfully"
} else {
throw NetworkError.timeout
}
}
func demonstrateAsync() async {
do {
let result = try await fetchData()
print(result)
} catch {
print("Async error: \(error)")
}
}
}
// 12. Error Logging with Context
class ErrorWithContext {
struct ErrorContext {
let operation: String
let timestamp: Date
let additionalInfo: [String: Any]
var description: String {
let info = additionalInfo.map { "\($0.key): \($0.value)" }.joined(separator: ", ")
return "[\(timestamp)] Operation '\(operation)' failed. Info: \(info)"
}
}
enum ContextualError: Error {
case operationFailed(context: ErrorContext)
case validationFailed(context: ErrorContext)
var localizedDescription: String {
switch self {
case .operationFailed(let context):
return "Operation failed - " + context.description
case .validationFailed(let context):
return "Validation failed - " + context.description
}
}
}
func performOperation(userId: String, value: Int) throws {
print("\n--- Error with Context ---")
guard !userId.isEmpty else {
let context = ErrorContext(
operation: "performOperation",
timestamp: Date(),
additionalInfo: ["userId": userId, "reason": "empty"]
)
throw ContextualError.validationFailed(context: context)
}
guard value > 0 else {
let context = ErrorContext(
operation: "performOperation",
timestamp: Date(),
additionalInfo: ["userId": userId, "value": value]
)
throw ContextualError.operationFailed(context: context)
}
print("Operation succeeded for user \(userId) with value \(value)")
}
func demonstrateContext() {
do {
try performOperation(userId: "user123", value: 10)
} catch let error as ContextualError {
print("Error: \(error.localizedDescription)")
}
do {
try performOperation(userId: "", value: 10)
} catch let error as ContextualError {
print("Error: \(error.localizedDescription)")
}
}
}
// Main demonstration
func demonstrateExceptionCatching() {
print("=== macOS Swift Exception Catching Examples ===")
// 1. Basic error handling
let basic = BasicErrorHandling()
basic.demonstrateBasicCatch()
// 2. Multiple catch blocks
let multiCatch = MultipleCatchBlocks()
multiCatch.demonstrateMultipleCatches()
// 3. Optional try
let optionalTry = OptionalTry()
optionalTry.demonstrateOptionalTry()
// 4. Force try
let forceTry = ForceTry()
forceTry.forceUnwrapDemo()
// 5. Defer
let deferExample = DeferExample()
deferExample.demonstrateDefer()
deferExample.multipleDefer()
// 6. Rethrowing
let rethrow = RethrowingExample()
rethrow.demonstrateRethrow()
// 7. Error propagation
let propagation = ErrorPropagation()
propagation.demonstratePropagation()
// 8. Result type
let resultType = ResultTypeExample()
resultType.demonstrateResult()
// 9. Comprehensive handler
let comprehensive = ComprehensiveErrorHandler()
comprehensive.demonstrateComprehensive()
// 10. Error with context
let context = ErrorWithContext()
context.demonstrateContext()
print("\n=== All Exception Catching Examples Completed ===")
}
// Run demonstration
demonstrateExceptionCatching()
💻 Registro de Logs swift
🟡 intermediate
⭐⭐⭐
Implementar sistema integral de registro con salida a archivo, niveles y rotación
⏱️ 30 min
🏷️ swift, macos, logging
Prerequisites:
Intermediate Swift, File I/O
// macOS Swift Logging Examples
// Comprehensive logging with file output, levels, and rotation
import Foundation
import OSLog
// 1. Simple Print Logging
class SimpleLogger {
func log(message: String) {
print("[LOG] \(message)")
}
func logInfo(message: String) {
print("[INFO] \(message)")
}
func logWarning(message: String) {
print("[WARNING] \(message)")
}
func logError(message: String) {
print("[ERROR] \(message)")
}
func demonstrateSimpleLogging() {
print("\n--- Simple Print Logging ---")
logInfo(message: "Application started")
logWarning(message: "This is a warning")
logError(message: "An error occurred")
log(message: "Custom log message")
}
}
// 2. Custom Logger with Levels
enum LogLevel: String, Comparable {
case debug = "DEBUG"
case info = "INFO"
case warning = "WARNING"
case error = "ERROR"
case critical = "CRITICAL"
static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
let order: [LogLevel] = [.debug, .info, .warning, .error, .critical]
return order.firstIndex(of: lhs)! < order.firstIndex(of: rhs)!
}
}
struct LogEntry {
let timestamp: Date
let level: LogLevel
let message: String
let file: String
let function: String
let line: Int
var formatted: String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
let timeString = formatter.string(from: timestamp)
let fileName = URL(fileURLWithPath: file).lastPathComponent
return "[\(timeString)] [\(level.rawValue)] [\(fileName):\(line)] \(function): \(message)"
}
}
class CustomLogger {
static let shared = CustomLogger()
private var logs: [LogEntry] = []
private var minimumLevel: LogLevel = .debug
private let lock = NSLock()
private init() {}
func setMinimumLevel(_ level: LogLevel) {
lock.lock()
defer { lock.unlock() }
minimumLevel = level
}
func log(_ level: LogLevel, message: String, file: String = #file, function: String = #function, line: Int = #line) {
guard level >= minimumLevel else { return }
let entry = LogEntry(
timestamp: Date(),
level: level,
message: message,
file: file,
function: function,
line: line
)
lock.lock()
logs.append(entry)
lock.unlock()
print(entry.formatted)
}
func debug(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
log(.debug, message: message, file: file, function: function, line: line)
}
func info(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
log(.info, message: message, file: file, function: function, line: line)
}
func warning(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
log(.warning, message: message, file: file, function: function, line: line)
}
func error(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
log(.error, message: message, file: file, function: function, line: line)
}
func critical(_ message: String, file: String = #file, function: String = #function, line: Int = #line) {
log(.critical, message: message, file: file, function: function, line: line)
}
func getLogs() -> [LogEntry] {
lock.lock()
defer { lock.unlock() }
return logs
}
func clearLogs() {
lock.lock()
defer { lock.unlock() }
logs.removeAll()
}
}
// 3. File Logger
class FileLogger {
private let fileURL: URL
private let fileHandle: FileHandle?
private let dateFormatter: DateFormatter
init?(filename: String = "app.log") {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
fileURL = documentsPath.appendingPathComponent(filename)
// Create file if it doesn't exist
if !FileManager.default.fileExists(atPath: fileURL.path) {
FileManager.default.createFile(atPath: fileURL.path, contents: nil, attributes: nil)
}
// Open file handle
do {
fileHandle = try FileHandle(forWritingTo: fileURL)
fileHandle?.seekToEndOfFile()
} catch {
print("Failed to open log file: \(error)")
return nil
}
dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
}
deinit {
fileHandle?.closeFile()
}
func log(level: LogLevel, message: String) {
let timestamp = dateFormatter.string(from: Date())
let logLine = "[\(timestamp)] [\(level.rawValue)] \(message)\n"
if let data = logLine.data(using: .utf8) {
fileHandle?.write(data)
}
// Also print to console
print(logLine, terminator: "")
}
func readLogEntries(limit: Int = 100) -> [String] {
guard let content = try? String(contentsOf: fileURL) else {
return []
}
let lines = content.components(separatedBy: .newlines)
return Array(lines.suffix(limit))
}
func clearLogFile() {
try? "".write(to: fileURL, atomically: true, encoding: .utf8)
print("Log file cleared")
}
}
// 4. Rotating File Logger
class RotatingFileLogger {
private let baseURL: URL
private let maxFileSize: Int64
private let maxLogFiles: Int
private var currentFileLogger: FileLogger?
init(baseFilename: String = "app", maxFileSize: Int64 = 1024 * 1024, maxLogFiles: Int = 5) {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
baseURL = documentsPath
self.maxFileSize = maxFileSize
self.maxLogFiles = maxLogFiles
openNewLogFile()
}
private func openNewLogFile() {
let timestamp = DateFormatter().string(from: Date()).replacingOccurrences(of: " ", with: "_")
let filename = "app_\(timestamp).log"
currentFileLogger = FileLogger(filename: filename)
print("Opened new log file: \(filename)")
}
private func rotateLogFiles() {
let fileManager = FileManager.default
// Get existing log files
do {
let files = try fileManager.contentsOfDirectory(at: baseURL, includingPropertiesForKeys: [.fileSizeKey], options: [])
let logFiles = files.filter { $0.pathExtension == "log" }
.sorted { $0.lastPathComponent > $1.lastPathComponent }
// Remove old files if exceeding limit
if logFiles.count > maxLogFiles {
for i in maxLogFiles..<logFiles.count {
try? fileManager.removeItem(at: logFiles[i])
print("Removed old log file: \(logFiles[i].lastPathComponent)")
}
}
} catch {
print("Error rotating log files: \(error)")
}
}
func log(level: LogLevel, message: String) {
// Check if current file size exceeds limit
if let fileURL = currentFileLogger?.fileURL,
let attributes = try? FileManager.default.attributesOfItem(atPath: fileURL.path),
let fileSize = attributes[.size] as? Int64,
fileSize > maxFileSize {
currentFileLogger = nil
rotateLogFiles()
openNewLogFile()
}
currentFileLogger?.log(level: level, message: message)
}
}
// 5. Unified Logging (OSLog)
class OSLogLogger {
private let logger = Logger(subsystem: "com.example.app", category: "General")
init() {
print("\n--- OSLog / Unified Logging ---")
}
func logDebug(_ message: String) {
logger.debug("\(message)")
}
func logInfo(_ message: String) {
logger.info("\(message)")
}
func logError(_ message: String) {
logger.error("\(message)")
}
func logFault(_ message: String) {
logger.fault("\(message)")
}
// With privacy
func logWithPrivacy(_ message: String, userId: String) {
logger.log("User \(privacy: .public(userId)) performed action: \(message)")
}
func demonstrateOSLog() {
logDebug("This is a debug message")
logInfo("Application started")
logError("An error occurred")
logFault("Critical failure!")
logWithPrivacy("Logged in", userId: "user123")
print("Check Console.app for OSLog messages")
}
}
// 6. Structured Logging
struct StructuredLogEntry: Encodable {
let timestamp: Date
let level: String
let message: String
let context: [String: Any]
enum CodingKeys: String, CodingKey {
case timestamp, level, message, context
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(ISO8601DateFormatter().string(from: timestamp), forKey: .timestamp)
try container.encode(level, forKey: .level)
try container.encode(message, forKey: .message)
let contextData = try JSONSerialization.data(withJSONObject: context)
try container.encode(String(data: contextData, encoding: .utf8), forKey: .context)
}
}
class StructuredLogger {
private let entries: [StructuredLogEntry] = []
private let lock = NSLock()
func log(level: LogLevel, message: String, context: [String: Any] = [:]) {
var logContext = context
logContext["thread"] = Thread.current.isMainThread ? "main" : "background"
logContext["processId"] = ProcessInfo.processInfo.processIdentifier
let entry = StructuredLogEntry(
timestamp: Date(),
level: level.rawValue,
message: message,
context: logContext
)
lock.lock()
defer { lock.unlock() }
// In real implementation, would store entry
print("Structured: \(entry)")
}
func logRequest(endpoint: String, statusCode: Int, duration: TimeInterval) {
log(level: .info, message: "API Request completed", context: [
"endpoint": endpoint,
"statusCode": statusCode,
"duration_ms": duration * 1000
])
}
}
// 7. Performance Logger
class PerformanceLogger {
private var startTimes: [String: Date] = [:]
private let logger = CustomLogger.shared
func startOperation(_ name: String) {
startTimes[name] = Date()
logger.debug("Operation '\(name)' started")
}
func endOperation(_ name: String) {
guard let startTime = startTimes[name] else {
logger.warning("Operation '\(name)' was not started")
return
}
let duration = Date().timeIntervalSince(startTime)
startTimes.removeValue(forKey: name)
logger.info("Operation '\(name)' completed in \(String(format: "%.3f", duration))s")
}
func measure<T>(_ name: String, operation: () -> T) -> T {
startOperation(name)
let result = operation()
endOperation(name)
return result
}
async func measureAsync<T>(_ name: String, operation: () async throws -> T) async rethrows -> T {
startOperation(name)
let result = try await operation()
endOperation(name)
return result
}
}
// 8. Error Logger
class ErrorLogger {
private let logger = CustomLogger.shared
private let fileLogger: FileLogger?
init() {
fileLogger = FileLogger(filename: "errors.log")
}
func logError(_ error: Error, context: [String: Any] = [:], file: String = #file, function: String = #function, line: Int = #line) {
let fileName = URL(fileURLWithPath: file).lastPathComponent
var message = "Error in \(fileName):\(line) \(function): \(error.localizedDescription)"
if !context.isEmpty {
let contextString = context.map { "\($0.key)=\($0.value)" }.joined(separator: ", ")
message += " | Context: \(contextString)"
}
logger.error(message)
fileLogger?.log(level: .error, message: message)
}
func logException(_ exception: NSException) {
let message = "Exception: \(exception.name) - \(exception.reason ?? "No reason")"
logger.critical(message)
fileLogger?.log(level: .critical, message: message)
if let stackTrace = exception.callStackSymbols.joined(separator: "\n") as String? {
fileLogger?.log(level: .critical, message: "Stack trace:\n\(stackTrace)")
}
}
}
// 9. Network Request Logger
class NetworkLogger {
private let logger = CustomLogger.shared
func logRequest(url: String, method: String, headers: [String: String] = [:], body: Data? = nil) {
logger.info("API Request: \(method) \(url)")
if !headers.isEmpty {
logger.debug("Headers: \(headers)")
}
if let body = body, let jsonString = try? JSONSerialization.jsonObject(with: body, options: []) {
logger.debug("Body: \(jsonString)")
}
}
func logResponse(url: String, statusCode: Int, headers: [String: String] = [:], body: Data? = nil, duration: TimeInterval) {
let statusLevel = statusCode < 400 ? LogLevel.info : LogLevel.error
logger.log(statusLevel, message: "API Response: \(url) - Status: \(statusCode) - Duration: \(String(format: "%.3f", duration))s")
if let body = body, let jsonString = try? JSONSerialization.jsonObject(with: body, options: []) {
logger.debug("Response body: \(jsonString)")
}
}
func logNetworkError(url: String, error: Error) {
logger.error("API Error: \(url) - \(error.localizedDescription)")
}
}
// 10. Log Aggregation and Filtering
class LogAggregator {
private var loggers: [CustomLogger] = []
private let fileLogger: FileLogger
init() {
fileLogger = FileLogger(filename: "aggregated.log")!
}
func addLogger(_ logger: CustomLogger) {
loggers.append(logger)
}
func broadcast(level: LogLevel, message: String) {
for logger in loggers {
logger.log(level, message: message)
}
fileLogger.log(level: level, message: message)
}
func getLogsByLevel(_ level: LogLevel) -> [LogEntry] {
var filtered: [LogEntry] = []
for logger in loggers {
filtered.append(contentsOf: logger.getLogs().filter { $0.level == level })
}
return filtered
}
}
// Main demonstration
func demonstrateLogging() {
print("=== macOS Swift Logging Examples ===")
// 1. Simple logging
let simple = SimpleLogger()
simple.demonstrateSimpleLogging()
// 2. Custom logger
print("\n--- Custom Logger with Levels ---")
let logger = CustomLogger.shared
logger.setMinimumLevel(.info)
logger.debug("This won't be logged")
logger.info("Application starting...")
logger.warning("Configuration file not found, using defaults")
logger.error("Failed to connect to database")
logger.critical("System out of memory!")
// 3. File logger
print("\n--- File Logger ---")
if let fileLogger = FileLogger(filename: "demo.log") {
fileLogger.log(level: .info, message: "Application started")
fileLogger.log(level: .warning, message: "This is a warning")
fileLogger.log(level: .error, message: "An error occurred")
print("\nLog file entries:")
let entries = fileLogger.readLogEntries()
entries.forEach { print($0) }
}
// 4. OSLog
let osLog = OSLogLogger()
osLog.demonstrateOSLog()
// 5. Performance logger
print("\n--- Performance Logger ---")
let perfLogger = PerformanceLogger()
let result = perfLogger.measure("calculation") {
var sum = 0
for i in 1...1000 { sum += i }
return sum
}
print("Calculation result: \(result)")
// 6. Error logger
print("\n--- Error Logger ---")
let errorLogger = ErrorLogger()
do {
throw NSError(domain: "Test", code: 1, userInfo: [NSLocalizedDescriptionKey: "Test error"])
} catch {
errorLogger.logError(error, context: ["userId": "123", "action": "login"])
}
// 7. Network logger
print("\n--- Network Logger ---")
let networkLogger = NetworkLogger()
networkLogger.logRequest(url: "https://api.example.com/users", method: "GET")
networkLogger.logResponse(url: "https://api.example.com/users", statusCode: 200, duration: 0.234)
networkLogger.logNetworkError(url: "https://api.example.com/users", error: NSError(domain: "Network", code: -1009))
// 8. Structured logger
print("\n--- Structured Logger ---")
let structLogger = StructuredLogger()
structLogger.logRequest(endpoint: "/api/users", statusCode: 200, duration: 0.123)
print("\n=== All Logging Examples Completed ===")
}
// Run demonstration
demonstrateLogging()
💻 Validación de Parámetros swift
🟡 intermediate
⭐⭐⭐
Validar parámetros de función con predicados, validadores personalizados y mensajes de error
⏱️ 30 min
🏷️ swift, macos, validation
Prerequisites:
Intermediate Swift, Generics
// macOS Swift Parameter Validation Examples
// Comprehensive parameter validation with predicates and custom validators
import Foundation
// 1. Basic Validation Functions
struct Validator {
static func validateNotEmpty(_ value: String, fieldName: String = "Value") throws {
guard !value.isEmpty else {
throw ValidationError.emptyInput
}
}
static func validatePositive(_ value: Int, fieldName: String = "Value") throws {
guard value > 0 else {
throw ValidationError.outOfRange(min: 1, max: Int.max, value: value)
}
}
static func validateRange(_ value: Int, min: Int, max: Int, fieldName: String = "Value") throws {
guard value >= min && value <= max else {
throw ValidationError.outOfRange(min: min, max: max, value: value)
}
}
static func validateMinLength(_ value: String, minLength: Int, fieldName: String = "Value") throws {
guard value.count >= minLength else {
throw ValidationError.tooShort(length: value.count, minLength: minLength)
}
}
static func validateEmail(_ email: String) throws {
let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
guard emailPredicate.evaluate(with: email) else {
throw ValidationError.invalidFormat
}
}
static func validateURL(_ url: String) throws {
guard let _ = URL(string: url), url.hasPrefix("http") else {
throw ValidationError.invalidFormat
}
}
static func validatePhoneNumber(_ phone: String) throws {
let phoneRegex = "^[+]{0,1}[0-9]{6,14}$"
let phonePredicate = NSPredicate(format: "SELF MATCHES %@", phoneRegex)
guard phonePredicate.evaluate(with: phone) else {
throw ValidationError.invalidFormat
}
}
}
// 2. Validation Result
enum ValidationResult {
case valid
case invalid(reason: String)
var isValid: Bool {
if case .valid = self { return true }
return false
}
var reason: String? {
if case .invalid(let reason) = self { return reason }
return nil
}
}
// 3. Generic Validator
struct GenericValidator<T> {
let validations: [(T) -> ValidationResult]
init(@ValidationBuilder validations: () -> [(T) -> ValidationResult]) {
self.validations = validations()
}
func validate(_ value: T) -> ValidationResult {
for validation in validations {
let result = validation(value)
if case .invalid = result {
return result
}
}
return .valid
}
}
@resultBuilder
struct ValidationBuilder {
static func buildBlock(_ components: [(Any) -> ValidationResult]...) -> [(Any) -> ValidationResult] {
components.flatMap { $0 }
}
static func buildExpression(_ expression: (Any) -> ValidationResult) -> [(Any) -> ValidationResult] {
[expression]
}
}
// 4. Common Validators
extension GenericValidator {
static func notEmpty(fieldName: String = "Value") -> GenericValidator<String> {
GenericValidator {
[
{ value in
value.isEmpty ? .invalid(reason: "\(fieldName) cannot be empty") : .valid
}
]
}
}
static func minLength(_ length: Int, fieldName: String = "Value") -> GenericValidator<String> {
GenericValidator {
[
{ value in
value.count < length ? .invalid(reason: "\(fieldName) must be at least \(length) characters") : .valid
}
]
}
}
static func maxLength(_ length: Int, fieldName: String = "Value") -> GenericValidator<String> {
GenericValidator {
[
{ value in
value.count > length ? .invalid(reason: "\(fieldName) must not exceed \(length) characters") : .valid
}
]
}
}
static func range(min: Int, max: Int, fieldName: String = "Value") -> GenericValidator<Int> {
GenericValidator {
[
{ value in
value < min || value > max ? .invalid(reason: "\(fieldName) must be between \(min) and \(max)") : .valid
}
]
}
}
static func positive(fieldName: String = "Value") -> GenericValidator<Int> {
GenericValidator {
[
{ value in
value <= 0 ? .invalid(reason: "\(fieldName) must be positive") : .valid
}
]
}
}
static func email() -> GenericValidator<String> {
GenericValidator {
[
{ value in
let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let predicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
predicate.evaluate(with: value) ? .valid : .invalid(reason: "Invalid email format")
}
]
}
}
static func url() -> GenericValidator<String> {
GenericValidator {
[
{ value in
guard let url = URL(string: value) else {
return .invalid(reason: "Invalid URL format")
}
return url.scheme == "http" || url.scheme == "https" ? .valid : .invalid(reason: "URL must start with http:// or https://")
}
]
}
}
static func matches(_ regex: String, fieldName: String = "Value") -> GenericValidator<String> {
GenericValidator {
[
{ value in
let predicate = NSPredicate(format: "SELF MATCHES %@", regex)
predicate.evaluate(with: value) ? .valid : .invalid(reason: "\(fieldName) format is invalid")
}
]
}
}
static func custom(_ predicate: @escaping (T) -> Bool, errorReason: String) -> GenericValidator<T> {
GenericValidator {
[
{ value in
predicate(value) ? .valid : .invalid(reason: errorReason)
}
]
}
}
}
// 5. Combining Validators
class CombinedValidator {
func validateUsername(_ username: String) -> ValidationResult {
let validator = GenericValidator
.notEmpty(fieldName: "Username")
.minLength(3, fieldName: "Username")
.maxLength(20, fieldName: "Username")
.matches("^[a-zA-Z0-9_]+$", fieldName: "Username")
return validator.validate(username)
}
func validatePassword(_ password: String) -> ValidationResult {
let hasUpperCase = NSPredicate(format: "SELF MATCHES %@", ".*[A-Z]+.*")
let hasLowerCase = NSPredicate(format: "SELF MATCHES %@", ".*[a-z]+.*")
let hasNumber = NSPredicate(format: "SELF MATCHES %@", ".*[0-9]+.*")
let hasSpecial = NSPredicate(format: "SELF MATCHES %@", ".*[!@#$%^&*()_+]+.*")
let checks = [
hasUpperCase.evaluate(with: password),
hasLowerCase.evaluate(with: password),
hasNumber.evaluate(with: password),
hasSpecial.evaluate(with: password)
]
if password.count < 8 {
return .invalid(reason: "Password must be at least 8 characters")
}
if !checks.allSatisfy({ $0 }) {
return .invalid(reason: "Password must contain uppercase, lowercase, number, and special character")
}
return .valid
}
func validateAge(_ age: Int) -> ValidationResult {
let validator = GenericValidator
.range(min: 0, max: 150, fieldName: "Age")
return validator.validate(age)
}
func validateUser(name: String, email: String, age: Int) -> [String] {
var errors: [String] = []
switch validateUsername(name) {
case .invalid(let reason): errors.append(reason)
default: break
}
switch GenericValidator.email().validate(email) {
case .invalid(let reason): errors.append(reason)
default: break
}
switch validateAge(age) {
case .invalid(let reason): errors.append(reason)
default: break
}
return errors
}
}
// 6. Property Wrapper Validation
@propertyWrapper
struct ValidatedString {
private var value: String
private let validator: (String) -> ValidationResult
var wrappedValue: String {
get { value }
set {
let result = validator(newValue)
if case .valid = result {
value = newValue
} else {
print("Validation error: \(result.reason ?? "Unknown")")
}
}
}
init(wrappedValue: String, validator: @escaping (String) -> ValidationResult) {
self.value = wrappedValue
self.validator = validator
}
}
@propertyWrapper
struct ValidatedInt {
private var value: Int
private let validator: (Int) -> ValidationResult
var wrappedValue: Int {
get { value }
set {
let result = validator(newValue)
if case .valid = result {
value = newValue
} else {
print("Validation error: \(result.reason ?? "Unknown")")
}
}
}
init(wrappedValue: Int, validator: @escaping (Int) -> ValidationResult) {
self.value = wrappedValue
self.validator = validator
}
}
// 7. User Model with Validation
struct ValidatedUser {
@ValidatedString(validator: GenericValidator.notEmpty().minLength(3).validate)
var username: String
@ValidatedString(validator: GenericValidator.email().validate)
var email: String
@ValidatedInt(validator: GenericValidator.range(min: 18, max: 120).validate)
var age: Int
}
// 8. Async Validation
class AsyncValidator {
func validateUsernameAvailable(_ username: String) async throws -> Bool {
// Simulate API call
try await Task.sleep(nanoseconds: 500_000_000) // 0.5 seconds
let takenUsernames = ["admin", "root", "system", "user"]
return !takenUsernames.contains(username.lowercased())
}
func validateEmailExists(_ email: String) async throws -> Bool {
// Simulate API call
try await Task.sleep(nanoseconds: 500_000_000)
return email.contains("@example.com")
}
func validateUserAsync(username: String, email: String) async -> [String] {
var errors: [String] = []
// Sync validations first
switch GenericValidator.notEmpty().minLength(3).validate(username) {
case .invalid(let reason): errors.append(reason)
default: break
}
switch GenericValidator.email().validate(email) {
case .invalid(let reason): errors.append(reason)
default: break
}
if !errors.isEmpty { return errors }
// Async validations
async let usernameAvailable = validateUsernameAvailable(username)
async let emailExists = validateEmailExists(email)
do {
let available = try await usernameAvailable
if !available {
errors.append("Username is already taken")
}
} catch {
errors.append("Failed to check username availability")
}
do {
let exists = try await emailExists
if !exists {
errors.append("Email not found in system")
}
} catch {
errors.append("Failed to verify email")
}
return errors
}
}
// 9. Validation with Context
struct ValidationErrorWithContext {
let field: String
let message: String
let value: Any
var description: String {
return "\(field): \(message) (value: \(value))"
}
}
class ContextValidator {
func validateRegistration(data: [String: Any]) -> [ValidationErrorWithContext] {
var errors: [ValidationErrorWithContext] = []
if let username = data["username"] as? String {
if username.isEmpty {
errors.append(ValidationErrorWithContext(field: "username", message: "cannot be empty", value: username))
} else if username.count < 3 {
errors.append(ValidationErrorWithContext(field: "username", message: "must be at least 3 characters", value: username))
}
} else {
errors.append(ValidationErrorWithContext(field: "username", message: "is required", value: "nil"))
}
if let email = data["email"] as? String {
let result = GenericValidator.email().validate(email)
if case .invalid(let reason) = result {
errors.append(ValidationErrorWithContext(field: "email", message: reason, value: email))
}
}
if let age = data["age"] as? Int {
let result = GenericValidator.range(min: 18, max: 120, fieldName: "age").validate(age)
if case .invalid(let reason) = result {
errors.append(ValidationErrorWithContext(field: "age", message: reason, value: age))
}
}
return errors
}
}
// 10. Predefined Validation Rules
struct ValidationRule {
let name: String
let validate: (Any) -> ValidationResult
static let notEmpty = ValidationRule(name: "notEmpty") { value in
guard let str = value as? String else {
return .invalid(reason: "Value must be a string")
}
return str.isEmpty ? .invalid(reason: "cannot be empty") : .valid
}
static let positiveNumber = ValidationRule(name: "positiveNumber") { value in
guard let num = value as? Int else {
return .invalid(reason: "Value must be a number")
}
return num > 0 ? .valid : .invalid(reason: "must be positive")
}
static let emailFormat = ValidationRule(name: "emailFormat") { value in
guard let email = value as? String else {
return .invalid(reason: "Value must be a string")
}
return GenericValidator.email().validate(email)
}
}
class RuleBasedValidator {
func validate(value: Any, against rules: [ValidationRule]) -> [ValidationResult] {
return rules.map { $0.validate(value) }.filter { !$0.isValid }
}
}
// Main demonstration
func demonstrateParameterValidation() {
print("=== macOS Swift Parameter Validation Examples ===")
// 1. Basic validators
print("\n--- Basic Validators ---")
do {
try Validator.validateNotEmpty("test")
print("Not empty: valid")
} catch {
print("Error: \(error)")
}
do {
try Validator.validateEmail("[email protected]")
print("Email: valid")
} catch {
print("Error: \(error)")
}
do {
try Validator.validateRange(15, min: 10, max: 20)
print("Range: valid")
} catch {
print("Error: \(error)")
}
// 2. Generic validators
print("\n--- Generic Validators ---")
let usernameValidator = GenericValidator.notEmpty().minLength(3).maxLength(20)
print("Username 'ab': \(usernameValidator.validate("ab"))")
print("Username 'john': \(usernameValidator.validate("john"))")
let ageValidator = GenericValidator.range(min: 18, max: 120)
print("Age 15: \(ageValidator.validate(15))")
print("Age 25: \(ageValidator.validate(25))")
// 3. Combined validation
print("\n--- Combined Validator ---")
let combined = CombinedValidator()
let userErrors = combined.validateUser(name: "jo", email: "invalid-email", age: 15)
print("User validation errors:")
userErrors.forEach { print(" - \($0)") }
// 4. Context validation
print("\n--- Context Validation ---")
let contextValidator = ContextValidator()
let registrationData = [
"username": "ab",
"email": "not-an-email",
"age": 15
] as [String: Any]
let contextErrors = contextValidator.validateRegistration(data: registrationData)
print("Registration errors:")
contextErrors.forEach { print(" - \($0.description)") }
// 5. Password validation
print("\n--- Password Validation ---")
let combinedValidator = CombinedValidator()
print("Password 'abc': \(combinedValidator.validatePassword("abc"))")
print("Password 'abc123': \(combinedValidator.validatePassword("abc123"))")
print("Password 'Abc123!@': \(combinedValidator.validatePassword("Abc123!@"))")
// 6. Rule-based validation
print("\n--- Rule-Based Validation ---")
let ruleValidator = RuleBasedValidator()
let results = ruleValidator.validate(value: -5, against: [.positiveNumber, .notEmpty])
print("Validation results for -5:")
results.forEach { print(" - \($0)") }
// 7. Property wrappers
print("\n--- Property Wrapper Validation ---")
var user = ValidatedUser(username: "john_doe", email: "[email protected]", age: 25)
print("Initial user: \(user.username), \(user.email), \(user.age)")
user.username = "ja" // Will print validation error
user.email = "invalid" // Will print validation error
print("\n=== All Parameter Validation Examples Completed ===")
}
// Run demonstration
demonstrateParameterValidation()