iOS 8核心数据堆栈 – 致命错误:发现零,同时展开一个可选值
我对iOS开发比较陌生,决定实现自己的Core Data堆栈,取代Apple的默认堆栈。
我不得不在我的代码中进行更改(很明显),并能够弄清楚,但在这种情况下我不能。 这是我的代码:
import UIKit import CoreData class AddTableViewController: UITableViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { @IBOutlet weak var nameTextField:UITextField! @IBOutlet weak var locationTextField:UITextField! @IBOutlet weak var imageView:UIImageView! @IBOutlet weak var notesView:UITextView! var coreDataStack = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack var backpackerSpot:BackpackerSpot! var managedContext: NSManagedObjectContext! override func viewDidLoad() { super.viewDidLoad() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // TODO Give user the choice of the Photo Library or the Camera override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { if indexPath.row == 0 { if UIImagePickerController.isSourceTypeAvailable(.Camera) { let imagePicker = UIImagePickerController() imagePicker.allowsEditing = false imagePicker.delegate = self imagePicker.sourceType = .Camera self.presentViewController(imagePicker, animated: true, completion: nil) } } tableView.deselectRowAtIndexPath(indexPath, animated: true) } // FIXME image is being displayed in landscape if it is taken in portrait mode by default func imagePickerController(picker: UIImagePickerController!, didFinishPickingImage image: UIImage!, editingInfo: [NSObject : AnyObject]!) { imageView.image = image imageView.contentMode = UIViewContentMode.ScaleAspectFill imageView.clipsToBounds = true dismissViewControllerAnimated(true, completion: nil) } @IBAction func save() { //validation var errorField = "" // TODO have placeholder text in the NOTES field match up with the placholder text in the NAME and LOCATION fields. if nameTextField.text == "" { errorField = "name" } else if locationTextField.text == "" { errorField = "location" } else if notesView.text == "" { errorField = "notes" } if errorField != "" { let alertController = UIAlertController(title: "Error", message: "You must fill in \(errorField).", preferredStyle: .Alert) let doneAction = UIAlertAction(title: "OK", style: .Default, handler: nil) alertController.addAction(doneAction) self.presentViewController(alertController, animated: true, completion: nil) return } // If all fields are correctly filled in, extract the field value // Create Restaurant Object and save to data store // if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack.context { let entityBackpackerSpot = NSEntityDescription.entityForName("BackpackerSpot", inManagedObjectContext: coreDataStack.context) backpackerSpot?.spotName = nameTextField.text backpackerSpot?.spotLocation = locationTextField.text backpackerSpot?.spotImage = UIImagePNGRepresentation(imageView.image) backpackerSpot?.spotNote = notesView.text var error: NSError? if !managedContext.save(&error) { println("insert error: \(error!.localizedDescription)") return } // Execute the unwind segue and go back to the home screen performSegueWithIdentifier("unwindToHomeScreen", sender: self) } }
该应用程序启动正常,但是当我点击附加到保存function的UIButton,它崩溃,我得到以下错误:
fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)
debugging器突出显示的行是:
if !managedContext.save(&error) {
无可否认,我必须花更多的时间在Swift中使用Optionals,因为它们似乎经常成为我的麻烦来源,尽pipe通常我能够弄明白。 如果有人能指出我的方向是正确的,那就太好了。 谢谢。
编辑:这是我的核心数据堆栈:
import Foundation import CoreData class CoreDataStack { let model: NSManagedObjectModel let storeCoordinator: NSPersistentStoreCoordinator let context: NSManagedObjectContext let store: NSPersistentStore? let dbName = "BackpackerSpots" // these options do the migration for us let options = [NSInferMappingModelAutomaticallyOption:true, NSMigratePersistentStoresAutomaticallyOption: true] init() { //1 loading model from the file let bundle = NSBundle.mainBundle() let modelURL = bundle.URLForResource(dbName, withExtension: "momd") model = NSManagedObjectModel(contentsOfURL: modelURL!)! //2 store coordinator created using that model storeCoordinator = NSPersistentStoreCoordinator(managedObjectModel: model) //3 context context = NSManagedObjectContext() context.persistentStoreCoordinator = storeCoordinator //4. store let documentsURL = MyDocumentDirectory() let storeURL = documentsURL.URLByAppendingPathComponent(dbName) var error:NSError? store = storeCoordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeURL, options: nil, error: &error) if store == nil { println("error adding persistent store: \(error)") abort() } } func saveContext() { var error: NSError? if context.hasChanges && !context.save(&error) { println("Could not save. \(error), \(error?.description)") } } }
编辑:这是我的根视图控制器:
import UIKit import CoreData class BackpackerSpotTableViewController: UITableViewController, NSFetchedResultsControllerDelegate { var coreDataStack = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack // var backpackerSpot:BackpackerSpot! var managedContext: NSManagedObjectContext! var backpackerSpots:[BackpackerSpot] = [] var fetchResultController:NSFetchedResultsController! // Let's add some animations! override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) { // initial cell state cell.alpha = 0 // state after animations UIView.animateWithDuration(1.0, animations: { cell.alpha = 1}) } override func viewDidLoad() { super.viewDidLoad() var fetchRequest = NSFetchRequest(entityName: "BackpackerSpot") let sortDescriptor = NSSortDescriptor(key: "spotName", ascending: true) fetchRequest.sortDescriptors = [sortDescriptor] // if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).coreDataStack { let entityBackpackerSpot = NSEntityDescription.entityForName("BackpackerSpot", inManagedObjectContext: coreDataStack.context) fetchResultController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: coreDataStack.context, sectionNameKeyPath: nil, cacheName: nil) fetchResultController.delegate = self var error: NSError? var result = fetchResultController.performFetch(&error) backpackerSpots = fetchResultController.fetchedObjects as [BackpackerSpot] if result != true { println(error?.localizedDescription) } } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - Table view data source override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.backpackerSpots.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cellIdentifier = "Cell" let cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as CustomTableViewCell let backpackerSpot = backpackerSpots[indexPath.row] cell.nameLabel.text = backpackerSpot.spotName cell.thumbnailImageView.image = UIImage(data: backpackerSpot.spotImage) cell.locationLabel.text = backpackerSpot.spotLocation return cell } override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { } override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? { var deleteAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete",handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in // if let managedObjectContext = (UIApplication.sharedApplication().delegate as AppDelegate).managedObjectContext { let entityBackpackerSpot = NSEntityDescription.entityForName("BackpackerSpot", inManagedObjectContext: self.coreDataStack.context) let backpackerSpotToDelete = self.fetchResultController.objectAtIndexPath(indexPath) as BackpackerSpot self.managedContext.deleteObject(backpackerSpotToDelete) var error: NSError? if !self.managedContext.save(&error) { println("Could not save \(error), \(error?.description)") } }) deleteAction.backgroundColor = UIColor(red: 169.0/255.0, green: 37.0/255.0, blue: 50.0/255.0, alpha: 1.0) return [deleteAction] } func controllerWillChangeContent(controller: NSFetchedResultsController!) { tableView.beginUpdates() } func controller(controller: NSFetchedResultsController!, didChangeObject anObject: AnyObject!, atIndexPath indexPath: NSIndexPath!, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath!) { switch type { case .Insert: tableView.insertRowsAtIndexPaths([newIndexPath], withRowAnimation: .Fade) case .Delete: tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) case .Update: tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) default: tableView.reloadData() } backpackerSpots = controller.fetchedObjects as [BackpackerSpot] } func controllerDidChangeContent(controller: NSFetchedResultsController!) { tableView.endUpdates() } override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) { if segue.identifier == "showBackpackerSpotDetails" { if let row = tableView.indexPathForSelectedRow()?.row { let destinationController = segue.destinationViewController as DetailViewController destinationController.backpackerSpot = backpackerSpots[row] } } } @IBAction func unwindToHomeScreen(segue: UIStoryboardSegue) { } }
你还没有初始化你的NSManagedContext
variables。 使用默认的核心数据设置你可以这样做:
override func viewDidLoad() { if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate { managedContext = appDelegate.managedObjectContext } }
编辑:鉴于你的核心数据设置,你应该这样做:
override func viewDidLoad() { managedContext = coreDataStack.context }
- iOS核心数据何时保存上下文?
- xcodebuild:cdtool无法编译:DataModelCompile /path/to/coredatamodel.xcdatamodeld dyld:找不到符号:_OBJC_CLASS _ $ _ OS_object
- 尝试更改布尔属性时发生EXC_BAD_ACCESS错误
- 核心数据sorting描述符与NSDate,iOS与斯威夫特
- 从FavoriteTableView发送数据到DetailView?
- iOS的崩溃'NSInternalInconsistencyException',原因:'语句仍然是'核心数据caching相关?
- 为什么NSManagedObjectContext队列在主线程上执行?
- iOS:NSFetchResultsControllersorting瞬态属性(Swift)
- 撤消核心数据pipe理对象