-1

enter image description here

I made a simple medication program that all it does is every time I click Take Medication button it stores the current time in NSUserDefaults. Well, I'd like to make it where it instead saves the Date & Time to a file so I can then keep a log of all the Dates and Times I took the Medication.

How can I write to a file when the button is clicked? Also, I need help or instruction on how to use it for what I'm trying to do. I'm brand new to Swift and I'm trying to learn on my own as I go.

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
John Martin
  • 443
  • 1
  • 4
  • 7
  • 1
    I would recommend starting here to learn the basics about the FileManager: https://developer.apple.com/documentation/foundation/filemanager – rmp May 03 '18 at 00:34

2 Answers2

0

Try this:

// Append a string to a file with a terminator that defaults to newline
// Equivalent to WriteLine in some other languages
func append(string: String, terminator: String = "\n", toFileAt url: URL) throws {
    // The data to be added to the file
    let data = (string + terminator).data(using: .utf8)!

    // If file doesn't exist, create it
    guard FileManager.default.fileExists(atPath: url.path) else {
        try data.write(to: url)
        return
    }

    // If file already exists, append to it
    let fileHandle = try FileHandle(forUpdating: url)
    fileHandle.seekToEndOfFile()
    fileHandle.write(data)
    fileHandle.closeFile()
}

let url = URL(fileURLWithPath: "/path/to/file.log")
try append(string: "Line 1", toFileAt: url)
try append(string: "Line 2", toFileAt: url)

The function will throw an error if it can't write to the specified file for any reason.


Why not make the function accept the path as a String (/path/to/file.log) instead of a URL (file://path/to/file.log)? Apple encourages all paths to be represented by URL, even if they point to local files. A lot of the newer APIs only accept path-as-URL. FileManager is an old hangover from Objective-C. There are still a few functions (like fileExists(atPath:)) that have not been converted over to the Swifty way.

Code Different
  • 90,614
  • 16
  • 144
  • 163
0

This is how you can Append A new Line to a file at specific URL instead of Writing it (as Writing will Replace the previous stored content)

extension String
    {
        func appendLineToURL(fileURL: URL) throws
        {
            try (self + "\n").appendToURL(fileURL: fileURL)
        }
        func appendToURL(fileURL: URL) throws
        {
            let data = self.data(using: String.Encoding.utf8)!
            try data.append(fileURL: fileURL)
        }
    }
    //MARK: NSData Extension
    extension Data
    {
        func append(fileURL: URL) throws {
            if let fileHandle = FileHandle(forWritingAtPath: fileURL.path)
            {
                defer
                {
                    fileHandle.closeFile()
                }

                fileHandle.seekToEndOfFile()
                fileHandle.write(self)
            }
            else
            {
                try write(to: fileURL, options: .atomic)
            }
        }
    }

Usage

/// if want to add a New Line
let newLine = "your content\n"

/// if want to append just next to previous added line
let newLine = "your content"    
do
{
     //save
     try newLine.appendToURL(fileURL: path!)
}
catch
{
     //if error exists
     print("Failed to create file")
     print("\(error)")
}

Update this is how I am using this function

//MARK: Usage
    func updateCsvFile(filename: String) -> Void
    {
        //Name for file
        let fileName = "\(filename).csv"
        let path1 = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
        let documentDirectoryPath:String = path1[0]
        //path of file
        let path = NSURL(fileURLWithPath: documentDirectoryPath).appendingPathComponent(fileName)

        //Loop to save array //details below header
        for detail in DetailArray
        {
            let newLine = "\(detail.RecordString)\n"

            //Saving handler
            do
            {
                //save
                try newLine.appendToURL(fileURL: path!)
                showToast(message: "Record is saved")
            }
            catch
            {
                //if error exists
                print("Failed to create file")
                print("\(error)")
            }

            print(path ?? "not found")
        }
        //removing all arrays value after saving data
        DetailArray.removeAll()
    }
iOS Geek
  • 4,825
  • 1
  • 9
  • 30
  • This gives me error: Use of unresolved identifier 'path' – John Martin May 04 '18 at 10:26
  • I need a step by step guide on how to use this code. I don't know how to even use Extensions, I put it outside the class, then made a button and added the usage code to it . When i run it it says path is unresolved. – John Martin May 04 '18 at 10:28