读取核心数据时出错:ios swift



我正在分析来自该数据源的数据,并且它们被正确解析,然后我将数据(标题、价格和日期)保存到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. 使用标题和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 设置新NSManagedObject的标题
  2. 使用价格和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 设置新NSManagedObject的价格
  3. 使用日期和ID调用saveItem
    1. 创建新的NSManagedObject
    2. 设置新NSManagedObject的日期

您想要做的是:

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

或者更好:

  1. 使用标题、价格、日期和ID调用saveUpdateItem
    1. 如果项目存在,则提取它,否则创建它
    2. 更新项目

您将返回一个nil,因为您为每个过程创建THREE对象,而不是ONE

最新更新