设置CoreData的默认值

时间:2017-01-18 18:41:02

标签: ios swift core-data

我正在使用CoreData处理我的第一个项目,我有数据模型设置。

我有一个带有“添加”按钮的表视图,该按钮触发警报并允许用户输入字符串:

func handleAdd() {

    let alert = UIAlertController(title: "New Company", message: "Add a new company", preferredStyle: .alert)

    let saveAction = UIAlertAction(title: "Save", style: .default) {
        [unowned self] action in

        guard let textField = alert.textFields?.first,
            let newCompany = textField.text else {
                return
        }

        self.save(name: newCompany)
        self.tableView.reloadData()
    }

    let cancelAction = UIAlertAction(title: "Cancel", style: .default)

    alert.addTextField()
    alert.addAction(saveAction)
    alert.addAction(cancelAction)

    present(alert, animated: true)
}

将字符串添加到NSManagedObject数组中:

func save(name: String) {

    guard let appDelegate =
        UIApplication.shared.delegate as? AppDelegate else {
            return
    }

    // 1
    let managedContext =
        appDelegate.persistentContainer.viewContext

    // 2
    let entity =
        NSEntityDescription.entity(forEntityName: "Company",
                                   in: managedContext)!

    let company = NSManagedObject(entity: entity,
                                 insertInto: managedContext)

    // 3
    company.setValue(name, forKeyPath: "name")



    // 4
    do {
        try managedContext.save()
        companies.append(company)
    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
}

到目前为止所有看起来都不错,除了我希望应用程序启动时已有5个单元格,然后让用户按照自己的意愿添加/删除。如何设置我希望应用程序启动的5个默认值?我尝试将以下代码添加到viewWillAppear

    let entity =
        NSEntityDescription.entity(forEntityName: "Company",
                                   in: managedContext)!

    let company = NSManagedObject(entity: entity,
                                  insertInto: managedContext)

    company.setValue("Apple", forKeyPath: "name")
    company.setValue("Google", forKeyPath: "name")
    company.setValue("Facebook", forKeyPath: "name")
    company.setValue("Tesla", forKeyPath: "name")
    company.setValue("Twitter", forKeyPath: "name")

    self.save(name: "Apple")
    self.save(name: "Google")
    self.save(name: "Facebook")
    self.save(name: "Tesla")
    self.save(name: "Twitter")

在加载时,它们都会出现。然后,当我离开页面并返回时,它们会再次添加。我知道这是因为它们在viewWillAppear中并且每次加载页面时都会被调用。

Apple的文档(核心数据编程指南)作为初学者有点难以接受,但他们确实说过

  

对于小型数据集,请直接在代码中创建托管对象。

     

如果您使用iOS或创建非基于文档的OS X应用程序,则可以添加应用程序启动检查,以确定您为应用程序商店指定的位置是否存在文件。如果没有,则需要导入数据。

我相信第二个片段是我在我的案例中寻找的(如果我错了,请纠正我),但是我不确定如何实现它,所以任何帮助如何设置这些默认值,以便它们被添加一次(加载时),只有一次会非常感激!

以下是感兴趣的初始化者

var companies = [NSManagedObject]()
var container: NSPersistentContainer!
let managedContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let companyEntity = "Company"

编辑:代码添加到app delegate

    let vc = ViewController()
    let entity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)!
    let company = NSManagedObject(entity: entity,insertInto: managedContext)
    let userDefaults = UserDefaults.standard
    userDefaults.set(true, forKey: "firstRun")

    if userDefaults.valueForKey("firstRun") == true {

        company.setValue("Apple", forKeyPath: "name")
        company.setValue("Google", forKeyPath: "name")
        company.setValue("Facebook", forKeyPath: "name")
        company.setValue("Tesla", forKeyPath: "name")
        company.setValue("Twitter", forKeyPath: "name")

        vc.save(name: "Apple")
        vc.save(name: "Google")
        vc.save(name: "Facebook")
        vc.save(name: "Tesla")
        vc.save(name: "Twitter")

        userDefaults.set(false, forKey: "firstRun")
    }

2 个答案:

答案 0 :(得分:4)

根据我的评论和您的 - 显然是失败的 - 编辑后编码,这是一个如何实施firstRun的建议:

首先在applicationDidFinishLaunching中注册默认值,即使同时更改了默认值,也必须使用这些行。

let userDefaults = UserDefaults.standard
let defaultValues = ["firstRun" : true]
userDefaults.register(defaults: defaultValues)

然后检查值(UserDefaults是否具有bool(forKey功能)并创建公司。注册默认值的代码在使用值之前执行是非常重要的。

if userDefaults.bool(forKey: "firstRun") {

    let defaultCompanies = ["Apple", "Google", "Facebook", "Tesla", "Twitter"]
    let entity = NSEntityDescription.entity(forEntityName: "Company", in: managedContext)!

    for companyName in defaultCompanies {
        let company = NSManagedObject(entity: entity,insertInto: managedContext)
        company.setValue(companyName, forKey: "name") // not keyPath
        companies.append(company)
    }
    do {
        try managedContext.save()
        userDefaults.set(false, forKey: "firstRun")
    } catch let error as NSError {
        print("Could not save. \(error), \(error.userInfo)")
    }
}

在您的代码中,您正在创建一个公司并更改名称值 5 次而不保存此特定公司。实际上,代码什么都不做。

答案 1 :(得分:0)

当您尝试插入新公司时,更好的解决方案是简单地实现重复数据删除逻辑,而不是使用某种任意UserDefaults"firstRun"。通常,ID用于此目的。例如,伪代码解释可能类似于:

use id, table
if table has id {
    return table.get(id)
} else {
    table.insert(id)
}

使用实际的Swift实现,这将看起来完全不同,但这个想法保持不变。以下是我自己项目中某些CoreData代码的示例:

static internal func insert(at id: String?, into table: String?) -> Self?
{
    //unwrap managed object context and id
    guard let context = self.context, let id = id else { return nil }
    let tableName = table ?? self.entityName //the table name in CoreData
    let request: NSFetchRequest<Self> = NSFetchRequest(entityName: tableName)
    request.predicate = NSPredicate(format: "id == %@", id) //filter only results matching 'id'
    if let result = try? context.fetch(request), let object = result.first
    {
        //return the existing object
        return object
    }
    else if let entity = NSEntityDescription.entity(forEntityName: tableName, in: context)
    {
        //initialize and return a new object
        return self.init(entity: entity, insertInto: context)
    }
    return nil
}

就我而言,id是一个字符串,但对于你来说它可能是Int或其他东西。上面代码片段中的要点是使用某种唯一标识值(id),检查表中是否存在具有该标识值的现有条目,并根据结果1)返回现有对象或2 )插入一个新对象。

在应用程序中,这是一个好处,因为多次调用insert将不会创建多个对象。假设我们从未在ID为“abcd”的数据库中插入任何项目:

//object is inserted at "abcd":
let result = SomeModel.insert(at: "abcd", into: "tablename")
//since object at "abcd" exists now, this returns the existing object:
let result = SomeModel.insert(at: "abcd", into: "tablename")

如果这回答了您的问题,或者您是否需要对此实施进行更多说明,请与我们联系。您提到您对CoreData相对较新,因此其中一些可能会令人困惑。