我正在使用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")
}
答案 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相对较新,因此其中一些可能会令人困惑。