Reputation: 2395
I have an app I've made that has a UITableView
with todoItems
as an array
for it. It works flawlessly and I have an export button that creates a CSV file from the UITableView
data and emails it out:
// Variables
var toDoItems:[String] = []
var convertMutable: NSMutableString!
var incomingString: String = ""
var datastring: NSString!
// Mail alert if user does not have email setup on device
func showSendMailErrorAlert() {
let sendMailErrorAlert = UIAlertView(title: "Could Not Send Email", message: "Your device could not send e-mail. Please check e-mail configuration and try again.", delegate: self, cancelButtonTitle: "OK")
sendMailErrorAlert.show()
}
// MARK: MFMailComposeViewControllerDelegate Method
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismissViewControllerAnimated(true, completion: nil)
}
// CSV Export Button
@IBAction func csvExport(sender: AnyObject) {
// Convert tableView String Data to NSMutableString
convertMutable = NSMutableString();
for item in toDoItems
{
convertMutable.appendFormat("%@\r", item)
}
print("NSMutableString: \(convertMutable)")
// Convert above NSMutableString to NSData
let data = convertMutable.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
if let d = data { // Unwrap since data is optional and print
print("NSData: \(d)")
}
//Email Functions
func configuredMailComposeViewController() -> MFMailComposeViewController {
let mailComposerVC = MFMailComposeViewController()
mailComposerVC.mailComposeDelegate = self
mailComposerVC.setSubject("CSV File Export")
mailComposerVC.setMessageBody("", isHTML: false)
mailComposerVC.addAttachmentData(data!, mimeType: "text/csv", fileName: "TodoList.csv")
return mailComposerVC
}
// Compose Email
let mailComposeViewController = configuredMailComposeViewController()
if MFMailComposeViewController.canSendMail() {
self.presentViewController(mailComposeViewController, animated: true, completion: nil)
} else {
self.showSendMailErrorAlert() // One of the MAIL functions
}
}
My question is how do I create the same CSV file, but instead of emailing, save it to file? I'm new to programming and still learning Swift 2. I understand that the section of code (data!, mimeType: "text/csv", fileName: "TodoList.csv")
creates the file as an attachment. I've looked online for this and trying to understand paths and directories is hard for me. My ultimate goal is to have another UITableView
with a list of these 'saved' CSV files listed. Can someone please help? Thank you!
I added the following IBAction
to my project:
// Save Item to Memory
@IBAction func saveButton(sender: UIBarButtonItem) {
// Convert tableView String Data to NSMutableString
convertMutable = NSMutableString();
for item in toDoItems
{
convertMutable.appendFormat("%@\r", item)
}
print("NSMutableString: \(convertMutable)")
// Convert above NSMutableString to NSData
let data = convertMutable.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
if let d = data { // Unwrap since data is optional and print
print("NSData: \(d)")
}
let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
func writeToFile(_: convertMutable, path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws {
}
}
Upvotes: 2
Views: 9343
Reputation: 171
I was struggling to find a decent simple answer to this for ages.
Here is the best way that I've found to create a csv file and even the directory you want it to be it and write to it.
//First make sure you know your file path, you can get it from user input or whatever
//Keep the path clean of the name for now
var filePath = "/Users/Johnson/Documents/NEW FOLDER/"
//then you need to pick your file name
let fileName = "AwesomeFile.csv"
//You should probably have some data to put in it
//You can even convert your array to a string by appending all of it's elements
let fileData = "This,is,just,some,dummy,data"
// Create a FileManager instance this will help you make a new folder if you don't have it already
let fileManager = FileManager.default
//Create your target directory
do {
try fileManager.createDirectory(atPath: filePath!, withIntermediateDirectories: true, attributes: nil)
//Now it's finally time to complete the path
filePath! += fileName!
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
//Then simply write to the file
do {
// Write contents to file
try fileData.write(toFile: filePath!, atomically: true, encoding: String.Encoding.utf8)
print("Writing CSV to: \(filePath!)")
}
catch let error as NSError {
print("Ooops! Something went wrong: \(error)")
}
PS. Just noticed that question is from year ago, but I hope it helps a struggling newbie like myself when they inevitably stumble upon it like I did.
Upvotes: 3
Reputation: 4729
convertMutable
can be easily written to disk with either fun writeToFile(_ path: String, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
or func writeToURL(_ url: NSURL, atomically useAuxiliaryFile: Bool, encoding enc: UInt) throws
. All you have to do is create a path or URL to write the string out to. If you are using iCloud things will be more challenging but for locally stored files you can use let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
to get the root path of the documents directory.
Update: Based on you first comment below here is some added info: The first issue is that it appears as though you are looking for code you can just paste int your project without really understanding what it does. My appologies if I'm wrong, but if I'm right this is not a good route to take as you will have many issues down the road when things change.
At the bottom of your last code section you are trying to create a function inside a function which is not going to do what you want. The above mentioned functions are the declarations of two NSString functions not functions that you need to create. As NSMutableString is a subclass of NSString you can use those functions on your convertMutable
variable.
Another thing you need to deal with is creating a name for the file you want to save, currently you have pasted in the line above that gets the Documents directory but does not have a file name. You will need to devise a way to create a unique filename each time you save a CSV file and add that name to the end of path
. Then you can use writeToFile…
or writeToURL…
to write the string to the desired location.
If you find you don't fully comprehend the code you are adding then consider getting a book or finding classes about Swift (Coursera.org has a class that may be of use). There are plenty of resources out there learn the basics of software development and Swift, it will take effort and time but it will be worth it in the end if this is something you want to pursue.
Upvotes: 1