Hi,
I have a log to file function that as part of the logline inserts the current datetime as below:
class func logToFile(message: String, logInfo: LogInfo = appLogInfo, type: OSLogType = .default) {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.timeZone = TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())
formatter.locale = Locale(identifier: "en_US_POSIX")
let localDate = formatter.string(from: Date())
let logMessage = "\(localDate) [\(logInfo.category)] \(message)\n"
let documentDirPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let filePath = "\(documentDirPath)/\(logFileName)"
if let fileHandle = FileHandle.init(forWritingAtPath: filePath), let data = logMessage.data(using: .utf8) {
fileHandle.seekToEndOfFile()
fileHandle.write(data)
}
}
and it is always called from a serial queue:
Log.serialQueue.async {
logToFile(message: message, logInfo: logInfo, type: type)
}
Lately however, I am getting some crashes and I managed to catch one in the debugger. It happens when deallocating the local DateFormatter when exiting the logToFile function.
Xcode stops at the end of the function:
And the thread indicates that it is inside NSDateFormatter dealloc
and clicking on the ici::Dataformat destructor, the assembly code shows this:
And in the inspector, we can see that localDate is half-baked, it only contains the year and day:
I have found some posts on DateFormatter not being thread safe but that was way in the past. In my case I only want to convert a Date() to String.
Something is not working as expected and suggestions on how to improve it would be very welcome.
Thanks in advance
DateFormatter is now threadsafe, but creating one is quite expensive.
You certainly shouldn't be creating one every time you call logToFile!
So you might try using an extension, like this:
extension DateFormatter {
static let myFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"
formatter.timeZone = TimeZone(secondsFromGMT: TimeZone.current.secondsFromGMT())
formatter.locale = Locale(identifier: "en_US_POSIX")
return formatter
}()
}
(Give it a more meaningful name, of course)
Then in your logToFile, you can use it like this:
let localDate = DateFormatter.myFormatter.string(from: Date())
This will be more efficient, and should fix your issue.