从核心数据读取错误:ios swift

时间:2016-06-08 10:09:08

标签: ios swift core-data

我正在解析来自此data source的数据,并且它们被正确解析,然后我将数据(标题,价格和日期)保存到CoreData,标题保存并正确读取,价格和保存日期,但在阅读时发现它们为零。 错误是"致命错误:在展开可选值时意外发现nil"返回结果函数读取。 这是MyTableViewController.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.swift

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

}

1 个答案:

答案 0 :(得分:1)

您正在执行以下操作:

  1. 使用标题和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 在新NSManagedObject上设置标题
  2. 使用价格和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 在新NSManagedObject上设置价格
  3. 使用日期和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 在新NSManagedObject上设置日期
  4. 想要做的是:

    1. 使用标题和ID调用saveItem
      1. 创建新的NSManagedObject
      2. 在新NSManagedObject上设置标题
    2. 使用价格和ID调用updateItem
      1. 基于ID的FETCH现有对象
      2. 在新NSManagedObject上设置价格
    3. 使用日期和ID调用updateItem
      1. 基于ID的FETCH现有对象
      2. 在新的NSManagedObject上设置命运
    4. 或者更好:

      1. 使用标题,价格,日期和ID调用saveUpdateItem
        1. 获取项目(如果存在,否则创建它)
        2. 更新项目
      2. 您正在获得nil,因为您为每次传递创建 THREE 对象而不是 ONE 对象。