You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5日志写入代码在macOS Yosemite失效问题排查求助

问题诊断与修复方案

咱们先梳理下你的日志程序在macOS Yosemite(10.10)上失效的核心原因,再给出针对性的修复方案——毕竟新老系统的API行为、权限规则确实存在不少差异:

1. 目录创建的隐藏失败问题

你的defaultDirectory()方法里创建目录时用了:

try fileManager.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil)

withIntermediateDirectories: false意味着只有所有上级目录都存在时,才能创建最后一级Logs目录。但首次运行时TestingLog目录肯定不存在,这直接导致目录创建失败,后续日志写入自然无法进行。而Mojave可能因为系统权限或默认目录结构的变化,刚好让上级目录存在,所以能正常工作。

2. FileHandle的旧系统兼容性隐患

虽然你先创建了空文件,但FileHandle(forWritingAtPath:)在Yosemite上对文件权限的检查更严格;如果文件创建失败(比如目录不存在),这个方法会返回nil,你的代码直接跳过了写入逻辑,连错误提示都没有。

3. 路径拼接的不规范

用字符串硬拼接路径("\(url.path)/TestingLog/Logs")在旧系统中可能因为路径分隔符、特殊字符等问题出错,更安全的方式是用URL的appendingPathComponent方法来构建路径。

4. 完全缺失的错误日志

你的代码里几乎所有catch块都是空的,这导致你完全看不到Yosemite上到底哪里出了问题,根本没法定位故障。


修复后的完整代码

下面是修正后的Log.swift,解决了上述所有问题,同时保留了你需要的「追加日志、不删除原有内容」的核心需求:

import Foundation
open class Log {
    open var maxFileSize: UInt64 = 102400
    open var maxFileCount = 365
    ///The directory in which the log files will be written
    open var directory = Log.defaultDirectory() {
        didSet {
            directory = NSString(string: directory).expandingTildeInPath
            let fileManager = FileManager.default
            if !fileManager.fileExists(atPath: directory) {
                do {
                    try fileManager.createDirectory(atPath: directory, withIntermediateDirectories: true, attributes: nil)
                    NSLog("Successfully created log directory at \(directory)")
                } catch {
                    NSLog("Couldn't create directory at \(directory): \(error.localizedDescription)")
                }
            }
        }
    }
    open var currentPath: String {
        return "\(directory)/\(logName(0))"
    }
    ///The name of the log files
    open var name = "logfile"
    ///Whether or not logging also prints to the console
    open var printToConsole = true
    ///logging singleton
    open class var logger: Log {
        struct Static {
            static let instance: Log = Log()
        }
        return Static.instance
    }
    //the date formatter
    var dateFormatter: DateFormatter {
        let formatter = DateFormatter()
        formatter.timeStyle = .medium
        formatter.dateStyle = .medium
        // 为旧系统指定固定区域,避免日期格式异常
        formatter.locale = Locale(identifier: "en_US_POSIX")
        return formatter
    }
    ///write content to the current log file.
    open func write(_ text: String) {
        let path = currentPath
        let fileManager = FileManager.default
        
        // 双重保险:确保日志文件的上级目录存在
        let dirPath = (path as NSString).deletingLastPathComponent
        if !fileManager.fileExists(atPath: dirPath) {
            do {
                try fileManager.createDirectory(atPath: dirPath, withIntermediateDirectories: true, attributes: nil)
            } catch {
                NSLog("Failed to create log parent directory: \(error.localizedDescription)")
                return
            }
        }
        
        // 如果文件不存在,创建空文件
        if !fileManager.fileExists(atPath: path) {
            do {
                try "".write(toFile: path, atomically: true, encoding: .utf8)
            } catch {
                NSLog("Failed to create log file: \(error.localizedDescription)")
                return
            }
        }
        
        // 安全打开文件句柄,避免空指针操作
        guard let fileHandle = FileHandle(forWritingAtPath: path) else {
            NSLog("Failed to open file handle for path: \(path)")
            return
        }
        let dateStr = dateFormatter.string(from: Date())
        let writeText = "[\(dateStr)]: \(text)\n"
        defer { fileHandle.closeFile() } // 确保文件一定会被关闭,避免资源泄漏
        fileHandle.seekToEndOfFile()
        if let data = writeText.data(using: .utf8) {
            fileHandle.write(data)
        } else {
            NSLog("Failed to convert log text to UTF-8 data")
        }
        
        // 按需打印到控制台
        if printToConsole {
            print(writeText)
        }
    }
    ///Recursive method call to rename log files
    func rename(_ index: Int) {
        let fileManager = FileManager.default
        let path = "\(directory)/\(logName(index))"
        let newPath = "\(directory)/\(logName(index+1))"
        if fileManager.fileExists(atPath: newPath) {
            rename(index+1)
        }
        do {
            try fileManager.moveItem(atPath: path, toPath: newPath)
        } catch {
            NSLog("Failed to rename log file \(path) to \(newPath): \(error.localizedDescription)")
        }
    }
    ///gets the log name
    func logName(_ num :Int) -> String {
        return "\(name)-\(num).log"
    }
    ///get the default log directory
    class func defaultDirectory() -> String {
        let fileManager = FileManager.default
        // 用URL拼接路径更安全,避免字符串拼接的兼容性问题
        guard let libraryURL = fileManager.urls(for: .libraryDirectory, in: .userDomainMask).last else {
            NSLog("Failed to get library directory URL")
            return ""
        }
        let logDirURL = libraryURL.appendingPathComponent("TestingLog").appendingPathComponent("Logs")
        let path = logDirURL.path
        
        if !fileManager.fileExists(atPath: path) && !path.isEmpty {
            do {
                try fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
                NSLog("Default log directory created at \(path)")
            } catch {
                NSLog("Failed to create default log directory: \(error.localizedDescription)")
            }
        }
        return path
    }
}
///Writes content to the current log file
public func logw(_ text: String) {
    Log.logger.write(text)
}

关键修复点说明

  • 目录创建逻辑优化:把withIntermediateDirectories改为true,确保上级目录不存在时也能自动创建;同时在write方法里增加了目录存在性检查的双重保险。
  • 完善错误日志:所有catch块都添加了具体的错误信息打印,方便你在Yosemite上调试时快速定位问题。
  • FileHandle安全处理:用guard let检查FileHandle是否成功创建,避免空指针崩溃;同时用defer确保文件一定会被关闭,防止资源泄漏。
  • 路径拼接规范:用URL的appendingPathComponent构建目录路径,彻底避免字符串拼接带来的兼容问题。
  • DateFormatter兼容性优化:指定en_US_POSIX区域,避免旧系统上日期格式的异常显示。

这样修改后,你的日志功能应该能在macOS Yosemite上正常工作,同时完全满足「追加日志、保留原有内容」的需求。

内容的提问来源于stack exchange,提问作者BongJae Jeong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 00:44:08