Cue
Cue

Reputation: 3092

How to avoid to force unwrap a date .second component?

I'm using this code to create a document for a document base application for macOS, which hase as name the seconds elapsed since the Date() referencing date.

func saveDocumentInApplicationSupport() {
    do
    {
        // create a directory in Application Support
        let fileManager = FileManager.default
        let appSupportURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
        appSupportURL.appendingPathComponent("com.myCompany.myApp")
        let directoryURL = appSupportURL.appendingPathComponent("com.myCompany.myApp").appendingPathComponent("Documents")
        try fileManager.createDirectory (at: directoryURL, withIntermediateDirectories: true, attributes: nil)

        // set a name for the file
        let date = Date(timeIntervalSinceReferenceDate: 0) // "2001-01-01 00:00:00 +0000"
        let seconds = Calendar.current.dateComponents([.second], from: date, to: Date()).second // eg. 517848179

        let fileName = "\(seconds!).idoc" // avoid force unwrapping here
        // eg. 517848179.idoc

        //  Create document
        let documentURL = directoryURL.appendingPathComponent (fileName)
        try document.write (to: documentURL, ofType: "com.myCompany.idoc")
    }
    catch
    {
        print("An error occured")
    }
}

What is the correct way to avoid to force unwrap the seconds variable?

Upvotes: 0

Views: 694

Answers (2)

Sulthan
Sulthan

Reputation: 130172

let theDate = Date()

let date = Date(timeIntervalSinceReferenceDate: 0) // "2001-01-01 00:00:00 +0000"
let seconds = Calendar.current.dateComponents([.second], from: date, to: theDate).second!

is the same as directly calling:

let seconds = Int(theDate.timeIntervalSinceReferenceDate)

Upvotes: 3

Alexander
Alexander

Reputation: 63379

I think you're chasing a red herring. Your worried about this one force unwrap, yet your whole block of code is surrounded in a do/catch which contains multiple trys, completely ignores the error, and does little in the way of damage control.

My only suggestion would be to move the force unwrap to the definition of seconds:

func saveDocumentInApplicationSupport() {
    do {
        // create a directory in Application Support
        let fileManager = FileManager.default
        let appSupportURL = fileManager.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!
        appSupportURL.appendingPathComponent("com.myCompany.myApp")
        let directoryURL = appSupportURL.appendingPathComponent("com.myCompany.myApp").appendingPathComponent("Documents")
        try fileManager.createDirectory (at: directoryURL, withIntermediateDirectories: true, attributes: nil)

        // set a name for the file
        let date = Date(timeIntervalSinceReferenceDate: 0) // "2001-01-01 00:00:00 +0000"
        let seconds = Calendar.current.dateComponents([.second], from: date, to: Date()).second!

        let fileName = "\(seconds).idoc" // eg. 517848179.idoc

        //  Create document
        let documentURL = directoryURL.appendingPathComponent (fileName)
        try document.write (to: documentURL, ofType: "com.myCompany.idoc")
    }
    catch {
        print("An error occured")
    }
}

Force unwrapping is not universally "bad". Your use of the force unwrap operator is entirely justified because you just defined the dateComponents as having a .second component. In this case, even if you did use conditional binding to "safely" unwrap your optional, what would you do in the nil case?

Upvotes: 3

Related Questions