将数组保存到CoreData Swift

Wiz*_*zz 4 arrays persistence core-data ios swift

我想保存这种arraysCore Data:

let crypto1 = Cryptos(name: "Bitcoin", code: "bitcoin", symbol: "BTC", placeholder: "BTC Amount", amount: "0.0")
let crypto2 = Cryptos(name: "Bitcoin Cash", code: "bitcoinCash", symbol: "BCH", placeholder: "BCH Amount", amount: "0.0")
Run Code Online (Sandbox Code Playgroud)

这甚至可能吗?

我知道我可以创建一个像这样保存的数组......

let name = "Bitcoin"
let code = "bitcoin"
let symbol = "BTC"
let placeholder = "BTC Amount"
let amount = "0.0"
let cryptos = CryptoArray(context: PersistenceService.context)
cryptos.name = name
cryptos.code = code
cryptos.symbol = symbol
cryptos.placeholder = placeholder
cryptos.amount = amount
crypto.append(cryptos)
PersistenceService.saveContext()
Run Code Online (Sandbox Code Playgroud)

...但是当用户创建理论上无限数量的数组时,这似乎非常不方便.

对我来说,保存数据,加载,编辑和删除数据的最佳方法是什么?

Luk*_*kas 9

这是一个教程而不是直接答案的问题.我建议你花点时间阅读一下CoreData.话虽如此,你的问题听起来很通用,"在Swift中将数组保存到CoreData",所以我想逐步解释一个简单的实现并没有什么坏处:

第1步:创建模型文件(.xcdatamodeld)

在Xcode中,file - new - file - iOS选择Data Model

第2步:添加实体

在Xcode中选择文件,找到并单击Add Entity,命名您的实体(CryptosMO跟随),单击Add Attribute并添加您想要存储的字段.(在这种情况下name, code, symbol...所有类型String).我会忽略其他一切,但name为了方便.

步骤3生成这些实体的对象表示(NSManagedObject)

在Xcode中,Editor - Create NSManagedObject subclass按照步骤操作.

步骤4让我们创建这个子类的克隆

NSManagedObject不是线程安全的,所以让我们创建一个可以安全传递的结构:

struct Cryptos {
    var reference: NSManagedObjectID! // ID on the other-hand is thread safe. 

    var name: String // and the rest of your properties
} 
Run Code Online (Sandbox Code Playgroud)

第5步:CoreDataStore

让我们创建一个商店,让我们访问NSManagedObjectContexts:

class Store {
    private init() {}
    private static let shared: Store = Store()

    lazy var container: NSPersistentContainer = {

        // The name of your .xcdatamodeld file.
        guard let url = Bundle().url(forResource: "ModelFile", withExtension: "momd") else {
            fatalError("Create the .xcdatamodeld file with the correct name !!!")
            // If you're setting up this container in a different bundle than the app,
            // Use Bundle(for: Store.self) assuming `CoreDataStore` is in that bundle.
        }
        let container = NSPersistentContainer(name: "ModelFile")
        container.loadPersistentStores { _, _ in }
        container.viewContext.automaticallyMergesChangesFromParent = true

        return container
    }()

    // MARK: APIs

    /// For main queue use only, simple rule is don't access it from any queue other than main!!!
    static var viewContext: NSManagedObjectContext { return shared.container.viewContext }

    /// Context for use in background.
    static var newContext: NSManagedObjectContext { return shared.container.newBackgroundContext() }
}
Run Code Online (Sandbox Code Playgroud)

Store使用您的.xcdatamodeld文件设置持久性容器.

第6步:获取这些实体的数据源

Core Data附带NSFetchedResultsController从允许大量配置的上下文中获取实体,这里是使用此控制器的数据源支持的简单实现.

class CryptosDataSource {

    let controller: NSFetchedResultsController<NSFetchRequestResult>
    let request: NSFetchRequest<NSFetchRequestResult> = CryptosMO.fetchRequest()

    let defaultSort: NSSortDescriptor = NSSortDescriptor(key: #keyPath(CryptosMO.name), ascending: false)

    init(context: NSManagedObjectContext, sortDescriptors: [NSSortDescriptor] = []) {
        var sort: [NSSortDescriptor] = sortDescriptors
        if sort.isEmpty { sort = [defaultSort] }

        request.sortDescriptors = sort

        controller = NSFetchedResultsController(fetchRequest: request, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
    }

    // MARK: DataSource APIs

    func fetch(completion: ((Result) -> ())?) {
        do {
            try controller.performFetch()
            completion?(.success)
        } catch let error {
            completion?(.fail(error))
        }
    }

    var count: Int { return controller.fetchedObjects?.count ?? 0 }

    func anyCryptos(at indexPath: IndexPath) -> Cryptos {
        let c: CryptosMO = controller.object(at: indexPath) as! CryptosMO
        return Cryptos(reference: c.objectID, name: c.name)
    }
}
Run Code Online (Sandbox Code Playgroud)

我们从这个类的一个实例所需要的只是对象数count和给定indexPath的项.请注意,数据源返回结构Cryptos而不是实例NSManagedObject.

第7步:添加,编辑和删除的API

让我们添加这个api作为扩展NSManagedObjectContext:但在此之前,这些操作可能成功或失败,所以让我们创建一个枚举来反映:

enum Result {
    case success, fail(Error)
} 
Run Code Online (Sandbox Code Playgroud)

API:

extension NSManagedObjectContext {

    // MARK: Load data

    var dataSource: CryptosDataSource { return CryptosDataSource(context: self) }

    // MARK: Data manupulation

    func add(cryptos: Cryptos, completion: ((Result) -> ())?) {
        perform {
            let entity: CryptosMO = CryptosMO(context: self)
            entity.name = cryptos.name
            self.save(completion: completion)
        }
    }

    func edit(cryptos: Cryptos, completion: ((Result) -> ())?) {
        guard cryptos.reference != nil else { 
            print("No reference")
            return 
        }
        perform {
            let entity: CryptosMO? = self.object(with: cryptos.reference) as? CryptosMO
            entity?.name = cryptos.name
            self.save(completion: completion)
        }
    }

    func delete(cryptos: Cryptos, completion: ((Result) -> ())?) {
        guard cryptos.reference != nil else { 
            print("No reference")
            return 
        }
        perform {
            let entity: CryptosMO? = self.object(with: cryptos.reference) as? CryptosMO
            self.delete(entity!)
            self.save(completion: completion)
        }
    }

    func save(completion: ((Result) -> ())?) {
        do {
            try self.save()
            completion?(.success)
        } catch let error {
            self.rollback()
            completion?(.fail(error))
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

第8步:最后一步,用例

要获取主队列中存储的数据,请使用Store.viewContext.dataSource.要添加,编辑或删除项目,请确定是否要在主队列上使用viewContext,或者使用 任何任意队列(甚至是主队列)newContext或使用Store容器提供的临时后台上下文来使用Store.container.performInBackground...它来公开上下文.例如,添加密码:

let cryptos: Cryptos = Cryptos(reference: nil, name: "SomeName")
Store.viewContext.add(cryptos: cryptos) { result in
   switch result {
   case .fail(let error): print("Error: ", error)
   case .success: print("Saved successfully")
   }
}
Run Code Online (Sandbox Code Playgroud)

UITableViewController使用密码数据源的简单:

class ViewController: UITableViewController {

    let dataSource: CryptosDataSource = Store.viewContext.dataSource

    // MARK: UITableViewDataSource

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return dataSource.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        return tableView.dequeueReusableCell(withIdentifier: "YourCellId", for: indexPath)
    }
    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let cryptos: Cryptos = dataSource.anyCryptos(at: indexPath)
        // TODO: Configure your cell with cryptos values.
    }
}
Run Code Online (Sandbox Code Playgroud)