我正在实施Swift版本的Stanford CS193p任务(PhotoMania)。
我很困惑为什么我的NSObjectContext保存命令没有保存到我相信我创建的持久存储中。
该应用程序的目标是有两个标签栏: - 标签栏#1包含来自Flickr的近期照片。 - 标签栏#2包含我最近查看过的照片。这意味着每次用户点击Flickr照片单元格来查看图像时,我应该将该图像的信息存储在持久存储结构中,以便在标签栏#2中访问它。
以下是应用程序的结构:
1。 AppDelegate包含存储设置说明:
import UIKit
import CoreData
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var objectContext:NSManagedObjectContext?
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool {
self.objectContext = self.createMainQueueManagedObjectContext()
self.testModel()
return true
}
func testModel(){
var photoModel: Photo? = NSEntityDescription.insertNewObjectForEntityForName("Photo", inManagedObjectContext: self.objectContext!) as? Photo
photoModel!.title = "hi"
photoModel!.subtitle = "subtitle"
self.objectContext!.insertObject(photoModel)
self.objectContext!.save(nil)
println(self.objectContext!.persistentStoreCoordinator.persistentStores[0].objects)
}
func createManagedObjectModel()-> NSManagedObjectModel{
var managedObjectModel:NSManagedObjectModel?
let modelURL:NSURL = NSBundle.mainBundle().URLForResource("PhotoModel", withExtension: "momd")
managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL)
return managedObjectModel!
}
func createPersistentStoreCoordinator()-> NSPersistentStoreCoordinator{
var persistentStoreCoordinator:NSPersistentStoreCoordinator?
var managedObjectModel:NSManagedObjectModel = self.createManagedObjectModel()
let storeURL:NSURL = self.applicationDocumentsDirectory().URLByAppendingPathComponent("MOC.sqlite")
var error:NSError?
persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: managedObjectModel)
if (persistentStoreCoordinator?.addPersistentStoreWithType(NSSQLiteStoreType as String, configuration: nil, URL: storeURL, options: nil, error: &error) == nil){
NSLog("unresolved error %@, %@", error!, error!.userInfo)
abort()
}
return persistentStoreCoordinator!
}
func applicationDocumentsDirectory()-> NSURL{
var hello:NSURL = NSFileManager().URLsForDirectory(NSSearchPathDirectory.DocumentDirectory, inDomains: NSSearchPathDomainMask.UserDomainMask).last as NSURL
return hello
}
func createMainQueueManagedObjectContext()->NSManagedObjectContext{
var managedObjectContext:NSManagedObjectContext?
var coordinator:NSPersistentStoreCoordinator = self.createPersistentStoreCoordinator()
if (coordinator != nil){
managedObjectContext = NSManagedObjectContext(concurrencyType: NSManagedObjectContextConcurrencyType.MainQueueConcurrencyType)
managedObjectContext!.persistentStoreCoordinator = coordinator
}
return managedObjectContext!
}
}
2. 有一个UITableView子类从AppDelegate获取上下文:
class MyViewController: UITableViewController {
@IBOutlet weak var refresher: UIRefreshControl?
let appDelegate:AppDelegate = UIApplication.sharedApplication().delegate as AppDelegate
var objectContext:NSManagedObjectContext?{
didSet{
self.fetchDatabasePhotos()
}
}
var fetchController:NSFetchedResultsController?{
didSet{
self.tableView.reloadData()
}
}
override func viewDidLoad() {
self.objectContext = self.appDelegate.objectContext
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func fetchDatabasePhotos(){
let request:NSFetchRequest = NSFetchRequest(entityName: "Photo")
request.predicate = nil
request.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
self.fetchController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.objectContext, sectionNameKeyPath: nil, cacheName: nil)
println(self.fetchController!)
// println(self.fetchController!.fetchedObjects)
}
}
3. MyViewController有一个“JustPostedFlickr”子类来管理Flickr下载。 Flickr下载部分工作正常。但我尝试在表视图控制器和图像视图控制器之间的prepareforsegue中调用的方法中插入照片对象。这是被调用的方法:
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!) {
let indexPath:NSIndexPath = self.tableView.indexPathForCell(sender as UITableViewCell)
if (segue.identifier == "Display Photo"){
if (segue.destinationViewController.isKindOfClass(ImageViewController)){
self.prepareImageViewController(segue.destinationViewController as ImageViewController, photo: self.photos[indexPath.row] as NSDictionary)
}
}
}
func prepareImageViewController(ivc:ImageViewController, photo:NSDictionary){
ivc.imageURL = FlickrFetcher.URLforPhoto(photo, format: FlickrPhotoFormatLarge)
ivc.title = photo.valueForKeyPath(FLICKR_PHOTO_TITLE) as String
var photoModel: Photo! = NSEntityDescription.insertNewObjectForEntityForName("Photo", inManagedObjectContext: self.objectContext) as Photo
photoModel!.title = photo.valueForKeyPath(FLICKR_PHOTO_TITLE) as String
photoModel!.subtitle = photo.valueForKeyPath(FLICKR_PHOTO_DESCRIPTION) as String
photoModel!.photoURL = FlickrFetcher.URLforPhoto(photo, format: FlickrPhotoFormatLarge).absoluteString
photoModel!.created_date = NSDate()
println(self.objectContext!)
var theVar:Bool = self.objectContext!.save(nil)
println(theVar)
self.fetchDatabasePhotos()
}
self.objectContext!.save(xx)
始终返回true。
self.objectContext.registeredObjects
会返回正确的照片模型结构和值
但是,当我获取照片并打印获取的对象列表时,它总是返回nil。
标签栏#2(最近的照片)的控制器,它应该从fetchController获取内容。即使在我点击图片(应该填充存储空间)之后,fetchcontroller.fetchedObjects
方法每次都返回nil:
import UIKit
class RecentPhotosController: MyViewController {
override func viewDidAppear(animated: Bool) {
self.objectContext = self.appDelegate.createMainQueueManagedObjectContext()
super.viewDidAppear(animated)
println("I just appeared")
}
override func numberOfSectionsInTableView(tableView: UITableView!) -> Int {
var sections:Int = 0
let fetchSections = self.fetchController!.sections
if (fetchSections != nil){
sections = fetchSections.count
}
return sections
}
override func tableView(tableView: UITableView!, numberOfRowsInSection section: Int) -> Int {
var rows:Int = 0
let fetchRows = self.fetchController!.fetchedObjects
if (fetchRows != nil){
rows = fetchRows.count
}
return rows
}
override func tableView(tableView: UITableView!, cellForRowAtIndexPath indexPath: NSIndexPath!) -> UITableViewCell! {
let cell = tableView.dequeueReusableCellWithIdentifier("Recent Photo", forIndexPath: indexPath) as UITableViewCell
let photo:Photo = self.fetchController!.objectAtIndexPath(indexPath)! as Photo
cell.textLabel.text = photo.title as String
cell.detailTextLabel.text = photo.subtitle as String
return cell
}
}
最后:这是Photo模型:
import Foundation
import CoreData
class Photo: NSManagedObject {
@NSManaged var title: String
@NSManaged var subtitle: String
@NSManaged var created_date: NSDate
@NSManaged var photoURL: String
}
我的问题是:为什么NSObjectContext中的对象没有保存到存储?
最后:我现在正在模拟器上进行测试但是我不认为这是我的问题的根源,因为我实现了Swift版本的CS193p的Photomania(使用核心数据和持久存储)并且运行良好。
答案 0 :(得分:2)
您似乎有两个控制器类,每个控制器类都调用self.appDelegate.createMainQueueManagedObjectContext()
createMainQueueManagedObjectContext
为每个控制器创建一个新的上下文。这很好,但它也调用createPersistentStoreCoordinator
,为每个上下文创建一个新的持久性存储协调器。这是一个问题,因为现在你有两个商店协调员,每个都有自己的持久存储,竞相写入磁盘上的同一个文件。根据每个商店何时相对于其他商店读取或写入文件,谁知道会发生什么。
你可能想要做的是:
答案 1 :(得分:1)
我明白了。失败的原因是我在定义fetchController后没有调用performfetch方法。
let request:NSFetchRequest = NSFetchRequest(entityName: "Photo")
request.predicate = nil
request.sortDescriptors = [NSSortDescriptor(key: "title", ascending: true)]
var fetchController = NSFetchedResultsController(fetchRequest: request, managedObjectContext: self.objectContext, sectionNameKeyPath: nil, cacheName: nil)
fetchController.performFetch(nil)
这个代码(我从斯坦福大学的obj-C代码中汲取灵感)隐藏在课程预定的coredata控制器中。
如果有人对此问题感到困惑,可能的解决方案是确保在UITableView中定义fetchcontroller后或在需要调用数据的任何其他时间调用performfetch。
以下是您如何知道错误发生的原因:
1)通过添加以下脚本来运行模拟器时调试Sqlite:-com.apple.CoreData.SQLDebug 3 2)(级别3允许您检查对象的更新,级别1不会)
3)您的数据是否已插入,但您仍然无法看到它?确保你正在进行抓取!
说实话,我怀疑机器人很多人会因为这个错误被抓了2天但是如果我们是军团,这应该会有所帮助。