2016-06-08 48 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