【问题标题】:Export CoreData to CSV in Swift在 Swift 中将 CoreData 导出为 CSV
【发布时间】:2020-04-29 11:20:14
【问题描述】:

我希望用户能够将其所有“DiaryItem”CoreData 记录导出为 CSV。这是我的代码:

DiaryItem.swift

import Foundation
import CoreData

public class DiaryItem:NSManagedObject,Identifiable {
   @NSManaged public var createdAt:Date?
   @NSManaged public var title:String?
}

extension DiaryItem {
    static func getAllDiaryItems() -> NSFetchRequest<DiaryItem> {
        let request:NSFetchRequest<DiaryItem> = DiaryItem.fetchRequest() as! NSFetchRequest<DiaryItem>

        let sortDescriptor = NSSortDescriptor(key: "createdAt", ascending: true)

        request.sortDescriptors = [sortDescriptor]

        return request
     }
}

SettingsView.swift

    import SwiftUI
    import CoreData

    struct SettingsView: View {
    @FetchRequest(entity: DiaryItem.entity(), sortDescriptors: [
        NSSortDescriptor(keyPath: \DiaryItem.createdAt, ascending: false),
    ]) var diaryItems : FetchedResults<DiaryItem>

    var body: some View {
        VStack(alignment: .leading) {
            Button(action: {
                  self.exportDatabase()
               }) {
                  Text("Export")
                  }
        }
    }

    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 fileHandleError: NSError? = nil
        var fileHandle: FileHandle? = nil
        do {
            fileHandle = try FileHandle(forWritingTo: exportFileURL as URL)
        } catch {
            print("Error with fileHandle")
        }

       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
        ]
    }
}

func createExportString() -> String {
    var createdAt: Date?
    var title: String?

    var export: String = NSLocalizedString("createdAt, title \n", comment: "")
    for diaryItem in self.diaryItems {

            let createdAtvar = DiaryItem.value(forKey: "createdAt") as! Date?
            let titlevar = DiaryItem.value(forKey: "title") as! String?
            let createdAtString = createdAtvar
            let titleString = titlevar

            export += "\(titleString!),\(createdAtString!)\n"

    }
    print("This is what the app will export: \(export)")
    return export
    }
   }
}

不幸的是,当我在模拟器中运行它时,它会因错误而崩溃:

[SwiftUI] 环境中的上下文未连接到持久存储协调器:

我已经为此苦苦挣扎了好几个小时,任何帮助都将不胜感激!

【问题讨论】:

  • 与您的问题无关,但您不能使用 Swift 4,因为 SwiftUI 仅在 Swift 5 中可用。
  • @DávidPásztor 谢谢!我已经更新了。
  • 如果您使用的是最新版本,则无需将 Swift 版本添加到您的问题中。如果您省略版本,则每个都假定它是关于最新版本 :) 如果您询问新版本中的特定更改或询问旧版本,请仅使用特定于版本的标签。
  • @DávidPásztor 好的,谢谢你告诉我。
  • 您已经找到解决方案了吗?

标签: swift core-data swiftui


【解决方案1】:

您的 SwiftUI 视图可能是另一个视图层次结构(例如工作表)的一部分,并且不知道 managedObjectContext。

您需要在打开它的视图中将 moc 设置为其环境的一部分,如下所示:

.sheet(isPresented: self.$showSheet) {
        SheetView()
            .environment(\.managedObjectContext, self.moc)
    }

【讨论】:

    【解决方案2】:

    要改进您的代码,请尝试替换:

    struct SettingsView: View {
        @FetchRequest(entity: DiaryItem.entity(), sortDescriptors: [
            NSSortDescriptor(keyPath: \DiaryItem.createdAt, ascending: false),
        ]) var diaryItems : FetchedResults<DiaryItem>
    
        var body: some View {
    

    与:

    struct SettingsView: View {
        @Environment(\.managedObjectContext) var moc
        @FetchRequest(fetchRequest: DiaryItem.getAllDiaryItems()) var diaryItems: FetchedResults<DiaryItem>
    
        var body: some View {
    

    您已经找到了一种从托管对象轻松获取数据的方法,但无论如何您都是在 SettingsView 中手动进行的 - 使用 .getAllDiaryItems 来获取数据。您在文件中根本没有托管对象上下文 - 这是文件与数据库联系的方式。

    【讨论】:

    • 这不正确,获取请求不需要在你的类中指定moc,只需要它存在于环境中,查看我的答案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-12
    • 2013-01-08
    • 2015-12-12
    • 2010-11-03
    • 2017-11-25
    • 1970-01-01
    相关资源
    最近更新 更多