String inerpolation issue using swift 5...

I'm saving the last n log messages in user defaults as a means of tracing crashes. The log data includes a string that has an interpolated call to a function that returns a formatted time string. When I retrieve it later after a cold start by the app, I'm seeing the current time displayed rather than the time the log entry was saved.

I've tried using String(format: "%@", "\(timeStamp())" before saving the string in an effort to get the time stamp, but I'm still seeing the time the message is retrieved. I break pointed the function formatting the time and it doesn't appear to get called, but all the log messages in the string array have the same current time that is minutes after the original message was logged.

Is this expected behavior? Is there a way to ensure I have a static string that will reflect the original string result?

I'm using xcode 13.2.1.

Show your code.

I've tried using String(format: "%@", "(timeStamp())" before saving the string in an effort to get the time stamp, but I'm still seeing the time the message is retrieved.

Something doesn't sound right here. In the usage of timeStamp(), does this use a lazy variable to get the date/time? If so, that would explain what you are seeing. Can you provide the code for timeStamp()?

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

This is the exact code being used.


this is the where I'm getting the time stamp, message is a text string
        let messageToLog = "\(BaseTimeSupport.formatDateTime(.now)) - \(message)"


this is the time stamp formatter
    static func formatDateTime(_ date: Date, usingFormat: String = "MM/dd/yyyy HH:mm:ss") -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = .current
        dateFormatter.dateFormat = usingFormat
        dateFormatter.calendar = Calendar(identifier: .gregorian)
        return dateFormatter.string(from: date)
    }

I'm saving the last n log messages in user defaults as a means of tracing crashes. The log data includes a string that has an interpolated call to a function that returns a formatted time string. When I retrieve it later after a cold start by the app, I'm seeing the current time displayed rather than the time the log entry was saved.

Interesting. Thanks for sharing the code. There must be something else going on here as I am not able to reproduce this with the code you've provided with UserDefaults.

Running this brief example:


class BaseTimeSupport {

    static func formatDateTime(_ date: Date, usingFormat: String = "MM/dd/yyyy HH:mm:ss") -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.locale = .current
        dateFormatter.dateFormat = usingFormat
        dateFormatter.calendar = Calendar(identifier: .gregorian)
        return dateFormatter.string(from: date)
    }
    
}

let defaults = UserDefaults.standard
var logs: [String] = []
if let logArray = defaults.object(forKey: "Logs") as? [String] {
    logs = logArray
    print("Current Logs ---------------------")
    for log in logs {
        print(log)
    }
}

let message1 = "Interesting event 1"
let messageToLog1 = "Log 1: \(BaseTimeSupport.formatDateTime(.now)) - \(message1)"

logs.append(messageToLog1)

sleep(2) // Spread out the logs

let message2 = "Interesting event 2"
let messageToLog2 = "Log 2: \(BaseTimeSupport.formatDateTime(.now)) - \(message2)"
logs.append(messageToLog2)

defaults.set(logs, forKey: "Logs")

Does produce:

Current Logs ---------------------
Log 1: 03/01/2022 07:35:34 - Interesting event 1
Log 2: 03/01/2022 07:35:36 - Interesting event 2
Log 1: 03/01/2022 07:35:43 - Interesting event 1
Log 2: 03/01/2022 07:35:45 - Interesting event 2
Log 1: 03/01/2022 07:35:49 - Interesting event 1
Log 2: 03/01/2022 07:35:51 - Interesting event 2
Log 1: 03/01/2022 07:36:56 - Interesting event 1
Log 2: 03/01/2022 07:36:58 - Interesting event 2

So there must be something different about my example than what you have locally?

Matt Eaton
DTS Engineering, CoreOS
meaton3@apple.com

I appreciate the help.

I'll do some more detailed testing.

This sort of thing usually ends up being something silly.

You should show how you READ the posts. Maybe you just recompute the time there ? instead of reading what has been stored ?

Worth a thought for sure...

    static func relogSavedLogMessages() {
        reloggingSavedLogs = true
        let _savedLogMessages = Array(savedLogMessage)
        savedLogMessage = []
        for message in _savedLogMessages {
            logMessage(level: .info, functionName: #function, category: Constants.logging.music, formattedMessage: "Relogging - %@", parameters: message)
        }
        reloggingSavedLogs = false
        if crashNeedsToBeLogged {
            /// log the crash
            crashNeedsToBeLogged = false
            BaseLoggingSupport.logMessage(level: .crash, functionName: #function, category: Constants.logging.music, formattedMessage: "App Crash Detected")
            BaseUISupport.postErrorMessage("App Crash Detected", obj: nil, error: nil, errorType: .red)
        }
    }

BaseLoggingSupport.logMessage is essentially a wrapper around the OSLog functionality. I had starting the app before the api last changed and decided to ensure I would only have to adjust one location if it changed again.

I'm seeing the current time in the text such as

relogSavedLogMessage() - Relogging - 03/01/2022 12:57:53 - countOfFetch(table:Predicate:) - Success 72

The logging time stamp for when the relogging shows after it as 03/01 125753


String inerpolation issue using swift 5...
 
 
Q