2014-08-30 2 views
1

Stanford CS193p 지정 (PhotoMania)의 Swift 버전을 구현 중입니다.IOS ObjectContext가 True를 반환 함에도 불구하고 영구 저장소에 저장되지 않음

내 NSObjectContext 저장 명령이 내가 만든 것으로 생각하는 영구 저장소에 저장되지 않는 이유에 대해 혼란스러워합니다.

앱의 목적은 두 개의 탭 막대를 사용하는 것입니다. - 탭 막대 # 1에 최근 Flickr의 사진이 포함되어 있습니다. - 탭 모음 # 2는 가장 최근에 본 사진을 포함합니다. 즉, 사용자가 Flickr 사진 셀을 탭하여 이미지를 볼 때마다 이미지의 정보를 영구 저장 구조에 저장하여 탭 막대 # 2에서 액세스해야합니다. 여기

앱이 구성되어 방법은 다음과 같습니다

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은 AppDelegate에에서 컨텍스트를 유도 할 수있는 jQuery과 서브 클래스가 :

1 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. Flickr 다운로드를 관리하는 MyViewController의 "JustPostedFlickr"하위 클래스가 있습니다. 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이 반환됩니다.

fetchController에서 콘텐츠를 가져 오기로되어있는 탭 모음 # 2 (최근 사진) 컨트롤러입니다. 나는 (저장을 채워야하는) 이미지를 눌러 후에도마다 전무 fetchcontroller.fetchedObjects 메소드가 리턴 마지막으로

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 
    } 
} 

그리고 :

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의 객체가 저장 영역에 저장되지 않습니까?

마지막으로 : 지금 시뮬레이터에서 테스트 중이지만 CS193p의 Photomania (핵심 데이터 및 영구 저장소를 사용하는)의 Swift 버전을 구현했기 때문에 이것이 내 문제의 근원이 될 것이라고 기대하지 않습니다. .

답변

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 코드에서 영감을 받았다) 과정의 predelivered coredata 컨트롤러에 숨겨져 있었다.

이 문제로 어려움을 겪는 사람이 있으면 가능한 해결책은 UITableView에서 fetchcontroller를 정의한 후 또는 데이터를 호출해야하는 경우 performfetch를 호출하는 것입니다. 이 스크립트를 추가하여 시뮬레이터를 실행하는 동안 당신의 SQLite는 디버깅

1) : -com.apple.CoreData.SQLDebug 3 2) (레벨 3은 사용자가 점검 할 수있게 오류가 일어나고있는 방법을 알고 여기에

입니다 객체에 대한 업데이트는 레벨 1이 아님)

3) 데이터가 삽입되었지만 여전히 볼 수 없습니까? 가져 오기를 수행하고 있는지 확인하십시오!

솔직히 말해서 나는 많은 사람들이이 실수로 2 일 동안 잡힐 것으로 의심하지만, 우리가 군대에 속하는 경우에는 도움이 될 것입니다.

2

는 각 self.appDelegate.createMainQueueManagedObjectContext()

createMainQueueManagedObjectContext 각 컨트롤러에 대한 새로운 컨텍스트를 생성 호출이 개 컨트롤러 클래스를 가지고있는 것 같습니다. 괜찮아요. 그러나 각 컨텍스트에 대해 새로운 영구 저장소 코디네이터를 만드는 createPersistentStoreCoordinator을 호출합니다. 이는 이제 각자 고유의 영구 저장소가있는 두 개의 저장소 조정자가있어 디스크의 동일한 파일에 쓰기 작업을하는 것과 같은 문제입니다. 각 저장소가 다른 저장소를 기준으로 파일을 읽거나 쓸 때 따라야 할 상황을 누가 알 수 있습니까?

은 당신이 아마 일을 할 수 원하는 것은 다음 중 하나

  1. 이 두 컨트롤러가 공유하는 단일 관리 개체 컨텍스트를 사용합니다.
  2. 하나의 영구 저장소 조정자를 만들어 모든 관리되는 개체 컨텍스트에 제공하고 각 컨트롤러에 자체 컨텍스트를 제공합니다.
+0

그래서 내가 실수로 Context 객체를 만들었다는 것이 맞습니다. 이제는 각 컨트롤러가 appdelegate에서 컨텍스트를 호출하도록 해당 호출을 제거했습니다. 그리고 createMainQueueManagedObjectContext는 응용 프로그램 시작시 대리자에서 호출됩니다. 그러나 객체는 여전히 상점에 삽입되지 않습니다. 재정의 FUNC의 viewDidLoad에() { self.objectContext = self.appDelegate.objectContext super.viewDidLoad() } – Laurent

+0

내가 여러 상황에 맞는 문제를 해결하는 방법을 보여 코드의 예입니다 문제를 진단 할 수있는 정보가 충분하지 않습니다. 이 수업을 단계별로 실행하고 관찰 할 수있는 내용을 확인하십시오. 그 대상이 어떻게 구원 받았다는 것을 어떻게 알 수 있습니까? 두 번째 컨트롤러가 언제 페치 요청을합니까? 두 번째 컨트롤러가 언제 테이블보기를 새로 고 칩니 까? 객체가 두 번째 컨트롤러에서 사용할 수 없다는 것을 어떻게 알 수 있습니까? 이제 관리 대상 객체 컨텍스트가 어떻게 구성됩니까? – Laurent

+0

아마 '돈 : 여기 그런데 – Jonah