2016-06-08 49 views
0

我正在解析來自此data source的數據,並且它們被正確解析,然後我將數據(標題,價格和日期)保存到CoreData,標題被保存並正確讀取,價格和日期被保存,但是在閱讀時它們被發現爲零。 在函數讀取返回結果時,錯誤是「致命錯誤:在解包可選值時意外發現零」。 這是MyTableViewController.swift:從核心數據讀取時出錯:ios swift

import UIKit 
import CoreData 

class MyTableViewController: UITableViewController { 
@IBOutlet var songsTable: UITableView! 
let viewModel = ViewModel() 
var imageCache = [String:UIImage]() 
var songs = [NSManagedObject]() 
let firstDefaults = NSUserDefaults.standardUserDefaults() 
let secondDefaults = NSUserDefaults.standardUserDefaults() 


override func viewDidLoad() { 
    super.viewDidLoad() 
    self.refresh() 
    self.refreshControl = UIRefreshControl() 
    self.refreshControl?.addTarget(self, action: #selector(MyTableViewController.refresh), forControlEvents: .ValueChanged) 

} 

func refresh() { 
    viewModel.fetch { 
     dispatch_async(dispatch_get_main_queue()) { 
      self.tableView.reloadData() 
      self.refreshControl?.endRefreshing() 
     } 
    } 


} 


override func numberOfSectionsInTableView(tableView: UITableView) -> Int { 
    return self.viewModel.numberOfSections() 
} 

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return self.viewModel.numberOfItemsInSection(section) 
} 

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! MyTableViewCell 
    let integer: NSInteger = indexPath.row 

    if !firstDefaults.boolForKey("titlesSaved") { 
     saveItem(self.viewModel.titleForItemAtIndexPath(indexPath), id: integer, name: "title") 
     firstDefaults.setBool(true, forKey: "titlesSaved") 
    } 
    cell.songTitle.text = read(integer,item: "title") as String 

    //images are not displayed 
    cell.songImage?.image = UIImage(named: "Blank52.png") 
    let urlString = self.viewModel.imageForItemAtIndexPath(indexPath) 

    let imgURL: NSURL = NSURL(string: urlString)! 
    let request: NSURLRequest = NSURLRequest(URL: imgURL) 
    NSURLConnection.sendAsynchronousRequest(
     request, queue: NSOperationQueue.mainQueue(), 
     completionHandler: {(response: NSURLResponse?, data: NSData?, error: NSError?) -> Void in 
      if error == nil { 
       cell.songImage.image = UIImage(data: data!) 
      } 
    }) 

    let thumbnailURLString = self.viewModel.imageForItemAtIndexPath(indexPath) 
    let thumbnailURL = NSURL(string: thumbnailURLString)! 

    //if image is cached 
    if let img = imageCache[thumbnailURLString] { 
     cell.songImage?.image = img 
     print("image is cached") 
    } 
    else { 
     // The image isn't cached, download the img data 
     // We should perform this in a background thread 
     let request: NSURLRequest = NSURLRequest(URL: thumbnailURL) 
     let mainQueue = NSOperationQueue.mainQueue() 
     NSURLConnection.sendAsynchronousRequest(request, queue: mainQueue, completionHandler: { (response, data, error) -> Void in 
      if error == nil { 
       // Convert the downloaded data in to a UIImage object 
       let image = UIImage(data: data!) 
       // Store the image in to our cache 
       self.imageCache[thumbnailURLString] = image 
       // Update the cell 
       dispatch_async(dispatch_get_main_queue(), { 
        if let cellToUpdate = tableView.cellForRowAtIndexPath(indexPath) as! MyTableViewCell?{ 
         cellToUpdate.songImage?.image = image 
        } 
       }) 
      } 
      else { 
       print("Error: \(error!.localizedDescription)") 
      } 
     }) 
    } 

    return cell 
} 

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    if let detailsViewController: DetailsViewController = segue.destinationViewController as? DetailsViewController { 
     let songIndex = songsTable!.indexPathForSelectedRow 
     let integer: NSInteger = songIndex!.row 

     //if !secondDefaults.boolForKey("pricesAndDatesSaved") { 
      saveItem(self.viewModel.priceForItemAtIndexPath(songIndex!), id: integer, name: "price") 
      saveItem(self.viewModel.dateForItemAtIndexPath(songIndex!), id: integer, name: "date") 
      //secondDefaults.setBool(true, forKey: "pricesAndDatesSaved") 
     // } 
     detailsViewController.songPrice = read(integer,item: "price") as String 
     detailsViewController.songDate = read(integer,item: "date") as String 
     // detailsViewController.songPrice = self.viewModel.priceForItemAtIndexPath(songIndex!) 
     //detailsViewController.songDate = self.viewModel.dateForItemAtIndexPath(songIndex!) 

    } 
} 

func saveImage(id:Int,image:UIImage) 
{ 
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
    let managedContext = appDelegate.managedObjectContext 

    let entity = NSEntityDescription.entityForName("Song", 
                inManagedObjectContext: managedContext) 
    let options = NSManagedObject(entity: entity!, 
            insertIntoManagedObjectContext:managedContext) 

    let newImageData = UIImageJPEGRepresentation(image,1) 

    options.setValue(id, forKey: "index") 
    options.setValue(newImageData, forKey: "image") 


} 

func saveItem(item:String, id:Int, name: String) 
{ 
    print("my \(name) is \(item)") 
    print("my id is \(id)") 
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
    let managedContext = appDelegate.managedObjectContext 

    let entity = NSEntityDescription.entityForName("Song", 
                inManagedObjectContext: managedContext) 
    let options = NSManagedObject(entity: entity!, 
            insertIntoManagedObjectContext:managedContext) 

    options.setValue(id, forKey: "index") 
    switch name { 

    case "title": 
     options.setValue(item, forKey: "title") 
    case "price": 
     options.setValue(item, forKey: "price") 
    case "date": 
     options.setValue(item, forKey: "date") 

    default: 
     print("error in switch") 
    } 


    do{ 
     try managedContext.save() 

    } catch let error as NSError{ 
     print("could not save title \(error)") 
    } 

} 

func read(id: Int, item:String)-> NSString 
{ 
    print("my id in read func is \(id)") 
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate 
    let managedContext = appDelegate.managedObjectContext 
    let fetchRequest = NSFetchRequest(entityName: "Song") 
    var result: NSString? = nil 
    do { 
     let results = try managedContext.executeFetchRequest(fetchRequest) 
     let single_result = results[id] 

     switch item { 
     case "title": 
      result = single_result.valueForKey("title") as? NSString 
     case "price": 
      result = single_result.valueForKey("price") as? NSString 
     case "date": 
      result = single_result.valueForKey("date") as? NSString 

     default: 
      print("error in switch in read function") 
     } 

      print ("i am reading the \(item): \(result)") 
    }catch let error as NSError{ 
     print("could not fetch title \(error)") 
    } 
    return result! 
} 

這是DetailsViewController。迅速

import UIKit 
import CoreData 

class DetailsViewController: UIViewController { 

@IBOutlet weak var price: UILabel! 
@IBOutlet weak var releaseDate: UILabel! 
var song: ViewModel? 
var songPrice: String = "" 
var songDate: String = "" 

override func viewDidLoad() { 
    super.viewDidLoad() 
    price.text = "Price = \(self.songPrice)" 
    print(self.songPrice) 
    print(self.songDate) 
    releaseDate.text = "Release date is: \(self.songDate)" 
    // Do any additional setup after loading the view. 
} 

override func didReceiveMemoryWarning() { 
    super.didReceiveMemoryWarning() 
    // Dispose of any resources that can be recreated. 
} 

} 
+0

看來您每個核心數據條目總是隻保存一個屬性而不是全部三個。這是打算?這可能會導致錯誤。 – vadian

+0

是的,我打算這樣做。 @vadian – Reem

+0

然後,你必須確保讀取函數總是返回一個非可選值或將返回值更改爲可選(並且使用Swift本機類型'String'而不是'NSString') – vadian

回答

1

你正在做以下幾點:

  1. 呼叫saveItem與標題和ID
    1. 新NSManagedObject
  2. 呼叫saveItem創建新的NSManagedObject
  3. 組冠軍價格和ID 新的NSManagedObject
  1. 新NSManagedObject創建新的NSManagedObject
  2. 套裝價格
  • 日期和ID呼叫saveItem
    1. 創建新的NSManagedObject
    2. 設置日期

      在做什麼是:有標題和ID

      1. 呼叫saveItem
        1. 與價格上新NSManagedObject創建新的NSManagedObject
        2. 設置標題
      2. 呼叫的updateItem和ID
        1. FETCH現有對象bas編上編號
        2. 套裝價格在新的NSManagedObject
      3. 日期和ID
        1. 魂在新的NSManagedObject現有的基於ID對象
        2. 集命運
      呼叫的updateItem

      或更好:

      如果存在的話0
      1. 與標題,價格,日期和ID
        1. 呼叫saveUpdateItem取物品,否則創建
        2. 更新項目

      你得到一個nil回來,因爲你正在創建THERE對象而不是ONE每次傳遞的對象。

  • +0

    謝謝你,你是對的!我修好了。 – Reem