I am writing an app using SwiftUI. I am trying to export all entries of one Entity (NPTransactions, attributes: date (Date), type(String)) in Core Data into CSV file. I want to use Share Sheet, so users could for example save the file to their phones.
What I know how to do is: - create CSV file - save CSV file - open Share Sheet
The problem is: I don't know how to iterate through Entity entries and create new line of text in CSV file.
I wanted to create an array from my entity like this:
var transactions = [NPTransaction]()
Later on I was hoping to iterate through this array and add new line of text for every entry. But it doesn't work. No text is being added from this for loop.
My code is like this:
import SwiftUI
struct SettingsView: View {
@State private var isShareSheetShowing = false
var transactions = [NPTransaction]()
var body: some View {
NavigationView {
Button(action: shareButton)
{
HStack(alignment: .firstTextBaseline) {
Text("Export CSV")
.font(.headline)
Image(systemName: "square.and.arrow.up")
.font(.title)
}
}
}
.navigationBarTitle("Settings")
}
func shareButton() {
let fileName = "export.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
var csvText = "Date,Type\n"
// This test works
// for _ in 1...5 {
// csvText += "test 1, test 2\n"
// }
// This doesn't work
for transaction in transactions {
csvText += "\(transaction.date ?? Date()),\(transaction.type ?? "-")\n"
}
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
print(path ?? "not found")
var filesToShare = [Any]()
filesToShare.append(path!)
let av = UIActivityViewController(activityItems: filesToShare, applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
isShareSheetShowing.toggle()
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}
Is the problem with my for loop or should I make it a different way? For example using fetchRequest somehow?
Eureka! :) I was missing a @FetchRequest:
@FetchRequest(entity: NPTransaction.entity(), sortDescriptors: []) var transactions: FetchedResults<NPTransaction>
Full code below. Maybe it will be useful for someone else.
import SwiftUI
struct SettingsView: View {
@FetchRequest(entity: NPTransaction.entity(), sortDescriptors: []) var transactions: FetchedResults<NPTransaction>
@State private var isShareSheetShowing = false
var body: some View {
NavigationView {
Button(action: shareButton)
{
HStack(alignment: .firstTextBaseline) {
Text("Export CSV")
.font(.headline)
Image(systemName: "square.and.arrow.up")
.font(.title)
}
}
}
.navigationBarTitle("Settings")
}
func shareButton() {
let fileName = "export.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
var csvText = "Date,Type\n"
for transaction in transactions {
csvText += "\(transaction.date ?? Date()),\(transaction.type ?? "-")\n"
}
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf8)
} catch {
print("Failed to create file")
print("\(error)")
}
print(path ?? "not found")
var filesToShare = [Any]()
filesToShare.append(path!)
let av = UIActivityViewController(activityItems: filesToShare, applicationActivities: nil)
UIApplication.shared.windows.first?.rootViewController?.present(av, animated: true, completion: nil)
isShareSheetShowing.toggle()
}
}
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
}
}