Reputation: 91
When trying to pass data that has been called from CoreData, the error returned shows Thread 1: EXC_BAD_INSTRUCTION (code=EXC_i386_INVOP, subcode=0x0). The debugger reads
fatal error: unexpectedly found nil while unwrapping an Optional value
However, when I add print statements before assigning my variables to the textfields, the variables print out correctly. I am beyond lost. Any help would be appreciated.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let myVC = storyboard?.instantiateViewController(withIdentifier: "editInventoryItem") as! AddInventoryItemVC
var inventoryItemName: String = ""
var inventoryItemStock: Double = 0.0
var inventoryItemPG: Double = 0.0
var inventoryItemVG: Double = 0.0
let itemName = flavors[indexPath.row]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Inventory")
request.predicate = NSPredicate(format: "inventoryItemName ==%@", itemName)
if let result = try? context.fetch(request) {
for object in result as! [NSManagedObject] {
inventoryItemName = object.value(forKey: "inventoryItemName") as! String
inventoryItemStock = object.value(forKey: "inventoryItemStock") as! Double
inventoryItemPG = object.value(forKey: "inventoryItemPGPercent") as! Double
inventoryItemVG = object.value(forKey: "inventoryItemVGPercent") as! Double
}
} else {
}
myVC.itemName.text = inventoryItemName
myVC.itemStock.text = "\(inventoryItemStock)"
myVC.itemPG.text = "\(inventoryItemPG)"
myVC.itemVG.text = "\(inventoryItemVG)"
performSegue(withIdentifier: "editInventoryItem", sender: "")
}
EDIT: After applying Rinki's suggestions, Xcode gave me the following corrections and, upon running, still returns the same errors.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let itemName = flavors[indexPath.row]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Inventory")
request.predicate = NSPredicate(format: "inventoryItemName ==%@", itemName)
if let result = try? context.fetch(request) {
for object in result as! [NSManagedObject] {
inventoryItemName = object.value(forKey: "inventoryItemName") as! String
inventoryItemStock = object.value(forKey: "inventoryItemStock") as! Double
inventoryItemPG = object.value(forKey: "inventoryItemPGPercent") as! Double
inventoryItemVG = object.value(forKey: "inventoryItemVGPercent") as! Double
}
} else {
}
performSegue(withIdentifier: "editInventoryItem", sender: "")
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "editInventoryItem" {
let myVC = segue.destination as! AddInventoryItemVC
myVC.itemName.text = inventoryItemName
myVC.itemStock.text = "\(inventoryItemStock)"
myVC.itemPG.text = "\(inventoryItemPG)"
myVC.itemVG.text = "\(inventoryItemVG)"
}
}
UPDATE: After some printing, it now makes sense why the errors are returning. prepareForSegue()
is being called before didSelectRow
, so the value is currently nil, but I have no clue how to call the didSelectRow
before prepareForSegue()
is called.
EDIT: After doing some research and implementing a Singleton, I've fixed the issue. I've added an identifier
variable in the Singleton, changing the variable to editInventoryItem
when didSelectRow is called. On the second VC, I set up a simple if statement that compares identifier
to editInventoryItem
and fills the textfields in question.
Thank you all for all of your help. One error down, probably 5,000,000 to go! :D
Upvotes: 1
Views: 123
Reputation: 91
On the first ViewController, my code is as follows:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let itemName = flavors[indexPath.row]
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Inventory")
request.predicate = NSPredicate(format: "inventoryItemName ==%@", itemName)
if let result = try? context.fetch(request) {
for object in result as! [NSManagedObject] {
Singleton.sharedInstance.itemName = object.value(forKey: "inventoryItemName") as! String
Singleton.sharedInstance.itemStock = object.value(forKey: "inventoryItemStock") as! Double
Singleton.sharedInstance.itemPG = object.value(forKey: "inventoryItemPGPercent") as! Double
Singleton.sharedInstance.itemVG = object.value(forKey: "inventoryItemVGPercent") as! Double
}
} else {
}
Singleton.sharedInstance.identifier = "editInventoryItem"
}
My Singleton:
struct Singleton {
static var sharedInstance = Singleton()
var identifier = ""
var itemName = ""
var itemStock = 0.0
var itemVG = 0.0
var itemPG = 0.0
}
On the first ViewController, my implementing code is as follows:
override func viewDidAppear(_ animated: Bool) {
print(Singleton.sharedInstance.identifier)
print(Singleton.sharedInstance.itemName)
if Singleton.sharedInstance.identifier == "editInventoryItem" {
nicotineSwitch.isEnabled = false
VGSwitch.isEnabled = false
PGSwitch.isEnabled = false
itemName.text = Singleton.sharedInstance.itemName
itemStock.text = "\(Singleton.sharedInstance.itemStock)"
itemPG.text = "\(Singleton.sharedInstance.itemPG)"
itemVG.text = "\(Singleton.sharedInstance.itemVG)"
Singleton.sharedInstance.identifier = ""
}
}
Upvotes: 1
Reputation: 104
Maybe you can try with Singleton shared instance
.
Create a new Swift file of type NSObject
YourAppState.swift
class YourAppState : NSObject {
class var sharedInstance: YourAppState {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: YourAppState? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = YourAppState()
}
return Static.instance!
}
}
And with this you can do the following:
Create a new variable inside the shared instance file,
var inventoryItemName = ""
And before going to next VC or performing segue,
give the value to inventoryItemName = object.value(forKey: "inventoryItemName") as! String
. In the destination VC class pass the value like this.
self.itemName.text = YourAppState.sharedInstance().inventoryItemName
Just make sure you add the value before performing a segue.
Hope it helps, cheers!
Upvotes: 0
Reputation: 176
prepareForSegue() method will be called after calling performSegue:
performSegue(withIdentifier: "editInventoryItem", sender: nil)
Here you can send your data from SourceViewController to Destination View Controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if(segue.identifier == "editInventoryItem") {
let myVC = segue.destinationViewController as! NextViewController
myVC.itemName.text = inventoryItemName
myVC.itemStock.text = "\(inventoryItemStock)"
myVC.itemPG.text = "\(inventoryItemPG)"
myVC.itemVG.text = "\(inventoryItemVG)"
}
}
Upvotes: 1
Reputation: 8563
Your issue has nothing to do with core data, but your use of segues. The method performSegue is create a new viewController from the storyboard. myVC
that was created from instantiateViewController
is discarded at the end of the function. Instead use prepareForSegue:sender:
to add the values to the viewController.
Upvotes: 1