将数据保存到CoreData时为什么会出现错误?

时间:2016-01-31 05:31:27

标签: ios swift core-data error-handling

我正在构建一个具有“播放列表”功能的应用。用户可以创建新的空播放列表,然后向其中添加内容。

我决定使用Core Data来做到这一点。所以我做了一些研究并创建了这个对象模型:

enter image description here

其中话语实体表示播放列表中的项目。

我用来显示播放列表的视图控制器是UITableViewController。这是课程的一部分:

var playlists: [Playlists] = []
let dataContext: NSManagedObjectContext! = (UIApplication.sharedApplication().delegate as? AppDelegate)?.managedObjectContext

override func viewDidLoad() {
    if dataContext != nil {
        let entity = NSEntityDescription.entityForName("Playlist", inManagedObjectContext: dataContext)
        let request = NSFetchRequest()
        request.entity = entity
        let playlists = try? dataContext.executeFetchRequest(request)
        if playlists != nil {
            for item in playlists! {
                self.playlists.append(item as! Playlists)
                print((item as! Playlists).name)
            }
        }
    }
}

Playlists是由Xcode生成的NSManagedObject子类。在viewDidLoad中,我获取所有播放列表并将其放入self.playlists。另请注意,tableView已正确实施。

现在,当用户点击添加播放列表按钮时,我正在编写动作方法。我想显示一条警告,要求用户输入播放列表的名称。如果他/她没有输入任何内容,将显示failAlert。否则,我创建一个新的Playlist对象并将其名称设置为textfield的文本并将其保存在数据库中。这是代码:

@IBAction func addPlaylist(sender: UIBarButtonItem) {
    let alert = UIAlertController(title: "新播放列表", message: "请输入播放列表的名字", preferredStyle: .Alert)
    alert.addTextFieldWithConfigurationHandler({ (textField) -> Void in
        textField.placeholder = "名字"
    })
    alert.addAction(UIAlertAction(title: "确定", style: .Default, handler: { (action) -> Void in
        if alert.textFields?.first?.text == "" || alert.textFields?.first?.text == nil {
            let failAlert = UIAlertController(title: "失败", message: "播放列表名不能为空", preferredStyle: .Alert)
            failAlert.addAction(UIAlertAction(title: "确定", style: .Default, handler: nil))
            self.presentViewController(failAlert, animated: true, completion: nil)
            return
        }
        let newPlaylist = Playlists(entity: NSEntityDescription.entityForName("Playlist", inManagedObjectContext: self.dataContext)!, insertIntoManagedObjectContext: self.dataContext)
        newPlaylist.name = alert.textFields?.first?.text
        if let _ = try? self.dataContext.save() {
            print("Error occured")
        }
        self.tableView.reloadData()
    }))

    self.presentViewController(alert, animated: true, completion: nil)
}

如你所见,我写了这个:

newPlaylist.name = alert.textFields?.first?.text
if let _ = try? self.dataContext.save() {
    print("Error occured")
 }
 self.tableView.reloadData()

因此,如果保存过程中发生错误,则会打印Error occurred。当我通过单击添加播放列表按钮测试应用程序时,它会询问我播放列表的名称。所以我输入了一些随机字母,如ggg,不幸的是它打印Error occured!此外,表格视图仍然是空的。

我真的不明白为什么,并认为数据没有保存。但是当我再次运行应用程序时,我在表格视图中看到了ggg!这太奇怪了!发生错误但成功保存了数据!为什么是这样?错误是什么?

编辑:

很多答案都说save会返回Bool。但Xcode表示不会:

enter image description here

这显然是Void

这个词

2 个答案:

答案 0 :(得分:3)

NSManagedObject' save:方法returns a boolean

  

返回值

     

如果保存成功则为YES,否则为NO。

因此,if let语句不是正确的方法,因为即使保存成功,该方法也总会返回一些(布尔值),导致if内的语句运行

您应该使用带有do-catch语句的Swift错误处理功能:

do {
    try self.dataContext.save()
} catch let error as NSError {
    print("Error: \(error)")
}

More about error handling in Swift 2.0

但这只能解决您的保存问题,而不是新对象在您重新启动应用程序之前不会出现的问题。要解决这个问题,您需要了解重新加载数据的方式。

现在,您正在调用self.tableView.reloadData(),但您提供的代码显示您正在viewDidLoad中从数据库中提取对象。鉴于仅在首次加载视图时调用viewDidLoad,您添加的新对象将不会包含在self.playlists数组中。

您应该在保存后立即将self.playlists功能中的新播放列表添加到addPlaylist

self.playlists.append(item as! Playlists)

答案 1 :(得分:0)

根据Apple document,NSManagedObjectContext:save()如果保存成功则返回true,否则返回false。

保存数据时,您会看到以下代码的错误:

do {
    try self.dataContext.save()
} catch let error as NSError  {
    print("Error occurred")
}