ios - 为什么我存入CoreData会出错?

标签 ios swift core-data error-handling

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

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

enter image description here

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

我用来显示播放列表的 View Controller 是 UITableViewController。这是类(class)的一部分:

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 对象并将其名称设置为文本字段的文本并将其保存在数据库中。这是代码:

@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 occurred!此外,表格 View 仍然是空的。

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

编辑:

很多答案都说 save 返回一个 Bool。但是 Xcode 说它没有:

enter image description here

那分明是Void这个词!

最佳答案

NSManagedObjectsave: 方法 returns a boolean :

Return Value

YES if the save succeeds, otherwise NO.

因此,if let 语句不是正确的方法,因为即使保存成功,该方法也总是会返回一些东西( bool 值),导致 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 仅在首次加载 View 时调用,您添加的新对象将不会包含在 self.playlists 数组中。

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

self.playlists.append(item as! Playlists)

关于ios - 为什么我存入CoreData会出错?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35110679/

相关文章:

iphone - iOS - 全局异常处理程序

ios - Swift 3 - 异步作业后关闭 View Controller

ios - 如何在 Swift 中使用 (?) 和 (!)

ios - Swift 3 转换

core-data - 为什么在使用 Swift 的 XCTest 下运行时 executeFetchRequest 不返回子类对象?

cocoa - Coredata、EXC_BAD_ACCESS 或相关对象上的奇怪行为

IOS Firebase 按值查询访问

ios - 如何本地化时间段 (iOS/OSX)

android - 如何在 Kotlin 多平台项目的 iOS 模块中将字符串转换为字节数组?

ios - 如何通过索引属性从核心数据中获取对象?