我正在构建一个具有“播放列表”功能的应用。用户可以创建新的空播放列表,然后向其中添加内容。
我决定使用Core Data来做到这一点。所以我做了一些研究并创建了这个对象模型:
其中话语实体表示播放列表中的项目。
我用来显示播放列表的视图控制器是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表示不会:
这显然是Void
!
答案 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")
}