2

I am looking for a way to create separate files. For example: I have an application which has a form such as name, date etc. and when I press save, I want to save all the information in that form of the user into a file. Each time the form is filled in, I want a new file to be created for each user. The file will be saved in the documents directory of the application. The name of the file should come from the 'name' textfield of the form. I have looked at ways to create files in swift but the filename is always hardcoded in the path url and every time the form is filled out the information gets saved on the same file. I don't want to do this. Any solution or advice is appreciated, I can't seem to find any solution to this online (only how to create a file with a hardcoded file name, which I am already able to do).

import UIKit

class FormViewController: UIViewController {

    @IBOutlet weak var organdonationno: UITextField!
    @IBOutlet weak var donorage: UITextField!
    @IBOutlet weak var snodname: UITextField!
    @IBOutlet weak var donorshospital: UITextField!
    @IBOutlet weak var date: UITextField!
    @IBOutlet weak var ID: UITextField!

    var fileMgr: FileManager = FileManager.default
    var docsDir: String?
    var dataFile: String?

    override func viewDidLoad() {
        super.viewDidLoad()
        let filemgr = FileManager.default
        let dirPaths = filemgr.urls(for: .documentDirectory, in: .userDomainMask)
        dataFile = dirPaths[0].appendingPathComponent("path").path
        if filemgr.fileExists(atPath: dataFile!) {
            let databuffer1 = filemgr.contents(atPath: dataFile!)
            let databuffer2 = filemgr.contents(atPath: dataFile!)
            let databuffer3 = filemgr.contents(atPath: dataFile!)
            let databuffer4 = filemgr.contents(atPath: dataFile!)
            let databuffer5 = filemgr.contents(atPath: dataFile!)

            let datastring1 = NSString(data: databuffer1!, encoding: String.Encoding.utf8.rawValue)
            let datastring2 = NSString(data: databuffer2!, encoding: String.Encoding.utf8.rawValue)
            let datastring3 = NSString(data: databuffer3!, encoding: String.Encoding.utf8.rawValue)
            let datastring4 = NSString(data: databuffer4!, encoding: String.Encoding.utf8.rawValue)
            let datastring5 = NSString(data: databuffer5!, encoding: String.Encoding.utf8.rawValue)

            organdonationno.text = datastring1 as? String
            donorage.text = datastring2 as? String
            snodname.text = datastring3 as? String
            donorshospital.text = datastring4 as? String
            date.text = datastring5 as? String
        }
        // Do any additional setup after loading the view.
    }

    @IBAction func savdata(_ sender: Any) {
        let databuffer1 = (organdonationno.text)!.data(using: String.Encoding.utf8)
         let databuffer2 = (donorage.text)!.data(using:  String.Encoding.utf8)
         let databuffer3 = (snodname.text)!.data(using: String.Encoding.utf8)
         let databuffer4 = (donorshospital.text)!.data(using: String.Encoding.utf8)
         let databuffer5 = (date.text)!.data(using: String.Encoding.utf8)

        fileMgr.createFile(atPath: dataFile!, contents: databuffer1, attributes: nil)
        fileMgr.createFile(atPath: dataFile!, contents: databuffer2, attributes: nil)
        fileMgr.createFile(atPath: dataFile!, contents: databuffer3, attributes: nil)
        fileMgr.createFile(atPath: dataFile!, contents: databuffer4, attributes: nil)
        fileMgr.createFile(atPath: dataFile!, contents: databuffer5, attributes: nil)

    }
}
Dávid Pásztor
  • 40,247
  • 8
  • 59
  • 80
Aneesa
  • 113
  • 3
  • 10
  • 1
    Do not harcode filename. The name of the file should come from the 'name'+'date'+'creationTime' of the form. That will make unique filename. – luckyShubhra Jun 30 '17 at 11:30
  • show us ur working code. It would be helpful. – luckyShubhra Jun 30 '17 at 11:31
  • @luckyShubhra i have added the code, it does not work correctly as it only saves the date but does not save the rest of the information from the form. Please bear with me if any mistakes i am a newbie. Thank you – Aneesa Jun 30 '17 at 11:43
  • I have added ans for your reference do let me know if you any queries. – luckyShubhra Jun 30 '17 at 12:14
  • @luckyShubhra thank you for this example it is greatly appreciated and works how i need it to. Only question is when i read the file i see the word "Optional" how do i get rid of this and have the title organdonationno instead?. Thank you – Aneesa Jun 30 '17 at 13:05

2 Answers2

1

It only saves dates because you are creating file for every field by the same name. It overwritten by new file every time. Last file u create is of date, hence only date persists.If you want to save all form data for one user you can do it as below. You need to create dynamic filename for every form so it is overwritten.

@IBAction func savdata(_ sender: Any) {

 let fileName="\(organdonationno.text) + \(donorage.text) + \(snodname.text) + \(donorshospital.text) + (date.text) "

 let file = "\(fileName).txt" //this is the file. we will write to and read from it

 let text = fileName //just a text

 if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {

 let path = dir.appendingPathComponent(file)

 //writing
 do {
    try text.write(to: path, atomically: false, encoding: String.Encoding.utf8)
  }
  catch {/* error handling here */}

  //reading
  do {
     let text2 = try String(contentsOf: path, encoding: String.Encoding.utf8)
  }
 catch {/* error handling here */}
}

------EDIT--------

To remove Optional word to need to force unwrap the value by putting exclamation mark (!) after the object to need to unwrap.

 var canBeNil : String? = "shubhra"
 print(canBeNil)  // output Optional("shubhra")
 print(canBeNil!)  // output shubhra

if you need title as organdonationno just edit :

 let fileName="\(organdonationno.text)"
 let text = "\(organdonationno.text) + \(donorage.text) + \(snodname.text) + \(donorshospital.text) + (date.text) "

Just make sure your filename is unique so that is not overwritten.

Hope it helps. Happy Coding!!

luckyShubhra
  • 2,606
  • 1
  • 9
  • 18
  • Hi, thank you for this can i ask your assistance for something else relating to this topic if possible. If i was to save an image to this file how can i do this from a different view controller. so for example once i have saved the general details in to the .txt file i would want to take an image and then save that image to the same file. how can i choose to send that particular data into the same file. ThankYou for your assistance much appreciated. – Aneesa Jul 03 '17 at 12:15
  • @Aneesa I will be glad to help. You need to post this as new SO ques. – luckyShubhra Jul 04 '17 at 03:28
1

My solution seems similar above. You'd better use the info your user input from textfields to organize a unique name of your file. And I strongly recommend you to write a model to stored your property, and do the saving to disk job for your coding clearness' sake. I can give you an example I just wrote on my playground:

struct User {
let organdonationno: NSString
let donorage: NSString
let snodName: NSString
let donorshospital: NSString
let date: NSString
let ID: NSString

func saveToJSONFile() {
    guard let documentDirectoryUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }

    let pathComponent = ID.appending(".json")

    let array = NSArray(array: [organdonationno, donorage, snodName, donorshospital, date, ID])

    let fileURL = documentDirectoryUrl.appendingPathComponent(pathComponent)

    do {
        let data = try JSONSerialization.data(withJSONObject: array, options: [])
        try data.write(to: fileURL, options: .atomic)
    }
    catch {
        print(error)
    }
}

}

The code I'm writing is put the struct's properties into an NSArray that it can be easily serialized as a JSON object. JSON is a type of well-displayed data structure. When it's written to your disk file, you can open the .json file to see inside. It will be like [ string1, string2, string3, string4, string5, string6] thing, which is pretty easy to understand.
and you can use it this way:

let user = User(organdonationno: datastring1, donorage: datastring2, snodName: datastring3, donorshospital: datastring4, date: datastring5, ID: datastring6)
user.saveToJSONFile()

If you're using swift 4, there is a convenient way to turn the User struct in to JSON object. You just need to let the User conform to Codable, and the apple's underlying implementation will do all of the work.

Struct User: Codable {
  • ThankYou for this example. However i get this error when i run the code. "Expression was too complex to be solved in reasonable time, consider breaking up the expressions into distinct sub-expressions". This is for the pathname "let pathComponent = organdonationno + donorage + snodName + donorshospital + date + ID + ".json" ". Any solutions to how i can fix this error. Also what if i was to just have the ID as the name of the .json file? I tried this but got a bunch of errors. – Aneesa Jun 30 '17 at 15:04
  • That's my mistake, I wrote it too fast to find out that the type of those string based properties is NSString. And in NSString, there is no such a '+' operator to use. So you should change that line to `let pathComponent = ID.appending(".json")` – Turtleeeeee Jul 03 '17 at 01:31