title: How does one export entries from coredata into a csv file to be emailed?
body: <p>Basically I have an app that takes in user input (in 5 textfields in an alertcontroller) that are all concatenated in to a string to be in a form that looks like it is a row in a csv file and stored to coredata as a entity. This entity will then be displayed in a tableview. I would like to be able to export the csv file to email it elsewhere. All this will be done in the iOS device itself.</p>
  
  <p>I have looked on this website and other websites but to no avail. A large majority of the example code makes use of outdated versions of swift and xcode.</p>
  
  <pre><code>class ViewController: UITableViewController, NSFetchedResultsControllerDelegate {
  
      let cellId = "cellId"
  
      fileprivate lazy var fetchedResultsController: NSFetchedResultsController&lt;AlarmItem&gt; = {
          //create fetch request
          let fetchRequest: NSFetchRequest&lt;AlarmItem&gt; = AlarmItem.fetchRequest()
  
          //configure fetch request
          fetchRequest.sortDescriptors = [NSSortDescriptor(key: "alarmAttributes", ascending: true)]
          let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
  
          let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
  
          let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
  
          fetchedResultsController.delegate = self
  
          return fetchedResultsController
      }()
  
      func controllerWillChangeContent(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;) {
          tableView.beginUpdates()
      }
  
      func controllerDidChangeContent(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;) {
          tableView.endUpdates()
      }
  
      func controller(_ controller: NSFetchedResultsController&lt;NSFetchRequestResult&gt;, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) {
  
          switch(type) {
          case .insert:
              if let indexPath = newIndexPath {
                  tableView.insertRows(at: [indexPath], with: .fade)
              }
              break;
          case .delete:
              if let indexPath = indexPath {
                  tableView.deleteRows(at: [indexPath], with: .fade)
              }
              break;
          case .update:
  
              if let indexPath = indexPath, let cell = tableView.cellForRow(at: indexPath) {
                  configureCell(cell, at: indexPath)
              }
              break;
          case .move:
              if let indexPath = indexPath {
                  tableView.deleteRows(at: [indexPath], with: .fade)
              }
              if let newIndexPath = newIndexPath {
                  tableView.insertRows(at: [newIndexPath], with: .fade)
              }
              break;
              @unknown default:
                  print("Something odd is happening")
              }
          }
  
  
          override func viewDidLoad() {
              super.viewDidLoad()
  
  
          override func viewWillAppear(_ animated: Bool) {
              super.viewWillAppear(animated)
              do {
                  try fetchedResultsController.performFetch()
          } catch let err as NSError {
              print("Failed to fetch items", err)
          }
      }
  
          @objc func addAlarmItem(_ sender: AnyObject) {
  
          let alertController = UIAlertController(title: "Add New Item", message: "Please fill in the blanks", preferredStyle: .alert)
          let saveAction = UIAlertAction(title: "Save", style: .default) { [unowned self] action in
  
              //combined string of attributes
              let myStrings: [String] = alertController.textFields!.compactMap { $0.text }
              let myText = myStrings.joined(separator: ", ")
  
              self.save(myText)
              self.tableView.reloadData()
          }
  
          let cancelAction = UIAlertAction(title: "Cancel", style: .destructive, handler: nil)
  
          alertController.addTextField { (textField) in
              textField.placeholder = "Enter Name of Engineer"
          }
          alertController.addTextField { (textField) in
              textField.placeholder = "Enter Date of Alarm in DD/MM/YYYY"
          }
          alertController.addTextField { (textField) in
              textField.placeholder = "Enter Time of Alarm in 24h (eg: 2300)"
          }
          alertController.addTextField { (textField) in
              textField.placeholder = "Please indicate True/False (type True or False)"
          }
          alertController.addTextField { (textField) in
              textField.placeholder = "Insert comments (if any), or NIL"
          }
  
  
      func save(_ itemName: String) {
          guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
          let managedContext = appDelegate.persistentContainer.viewContext
          let entity = NSEntityDescription.entity(forEntityName: "AlarmItem", in: managedContext)!
          let item = NSManagedObject(entity: entity, insertInto: managedContext)
          item.setValue(itemName, forKey: "alarmAttributes")
  
          do {
              try managedContext.save()
              tableView.reloadData()
  
          } catch let err as NSError {
              print("Failed to save an item", err)
          }
      }
  
  
   @objc func exportCSV(_ sender: AnyObject) {
          exportDatabase()
      }
  
      func exportDatabase() {
          let exportString = createExportString()
          saveAndExport(exportString: exportString)
      }
  
      func saveAndExport(exportString: String) {
          let exportFilePath = NSTemporaryDirectory() + "itemlist.csv"
          let exportFileUrl = NSURL(fileURLWithPath: exportFilePath)
          FileManager.default.createFile(atPath: exportFilePath, contents: NSData() as Data, attributes: nil)
          var fileHandle: FileHandle? = nil
  
          do {
              fileHandle = try FileHandle(forUpdating: exportFileUrl as URL)
          } catch {
              print("filehandle has error")
          }
  
          if fileHandle != nil {
              fileHandle!.seekToEndOfFile()
              let csvData = exportString.data(using: String.Encoding.utf8, allowLossyConversion: false)
              fileHandle!.write(csvData!)
              fileHandle!.closeFile()
  
              let firstActivityItem = NSURL(fileURLWithPath: exportFilePath)
              let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: [firstActivityItem], applicationActivities: nil)
  
              activityViewController.excludedActivityTypes = [
                  UIActivity.ActivityType.assignToContact,
                  UIActivity.ActivityType.saveToCameraRoll,
                  UIActivity.ActivityType.postToFlickr,
                  UIActivity.ActivityType.postToVimeo,
                  UIActivity.ActivityType.postToTencentWeibo
              ]
              self.present(activityViewController, animated: true, completion: nil)
          }
      }
  
      func createExportString() -&gt; String {
          var alarmAttributes: String?
          var export: String = NSLocalizedString("Engineer Name,Date of Alarm,Time of Alarm,True or False,Engineer Comments \n", comment: "")
  
          for (index, AlarmItem) in fetchedStatsArray.enumerated() {
              if index &lt;= fetchedStatsArray.count - 1 {
                  alarmAttributes = AlarmItem.value(forKey: "alarmAttributes") as! String?
                  let alarmAttributeStrings = alarmAttributes
                  export += "\(alarmAttributeStrings ?? "0") \n"
              }
          }
          print("the app will now print: \(export) ")
          return export
      }
  
          override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int{
              let sectionInfo = fetchedResultsController.sections![section]
              return sectionInfo.numberOfObjects
          }
  
          override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
              let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath)
              let alarmItem = fetchedResultsController.object(at: indexPath) as NSManagedObject
              cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
          return cell
      }
  
      func tableView(_ tableView: UITableView!, canEditRowAtIndexPath indexPath: NSIndexPath!) -&gt; Bool {
          return true
       }
  
      overr ide func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
          tableView.deselectRow(at: indexPath, animated: true)
       }
  
      override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
          guard editingStyle == .delete else { return }
  
      //fetch
              let toBeDeleted = fetchedResultsController.object(at: indexPath)
  
      //delete
          fetchedResultsController.managedObjectContext.delete(toBeDeleted)
  
          do {
              try fetchedResultsController.managedObjectContext.save()
          } catch let err as NSError {
          print("failed to save item", err)
          }
  
      }
  
      func tableView(_tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
          let cell = tableView.dequeueReusableCell(withIdentifier: "AlarmItem", for: indexPath)
          configureCell(cell, at: indexPath)
  
          return cell
      }
  
      func configureCell(_ cell: UITableViewCell, at indexPath: IndexPath) {
          let alarmItem = fetchedResultsController.object(at: indexPath)
  
          //configure cell
          cell.textLabel?.text = alarmItem.value(forKeyPath: "alarmAttributes") as? String
     }
  }
  </code></pre>