Reputation: 911
I have a table in swift CoreData in that I save records of OrderTable types and fetch saved records from that table to reload the table. with the help of closure, I assign that array value to an array of OrderTable type that stores all records and print values in the loop but when I reload a cell from that array it prints nil value when accessing key for that object.
Please help me on that I tried everything. Here're my code and attached a screenshot of problems.
https://i.sstatic.net/sXbrZ.png
##OrderTable.swift database model file
## Save records in database
class OrderTable: NSManagedObject {
// Insert code here to add functionality to your managed object subclass
class func createInManagedObjectContext(moc: NSManagedObjectContext, dict:[String:AnyObject]) -> OrderTable {
let newItem = NSEntityDescription.insertNewObjectForEntityForName("OrderTable", inManagedObjectContext: moc) as? OrderTable
newItem?.closedDate = dict["closedDate"]as? String;
newItem?.modifiedDate = dict["modifiedDate"]as? String
newItem?.openedDate = dict["openedDate"]as? String
newItem!.items = dict["items"]as? NSData
newItem?.server = (dict["server"]as? String?)!
newItem?.orderNo = dict["orderNo"]as? String
newItem?.totalPrice = dict["totalPrice"]as? String
newItem?.tableName = dict["tableName"]as? String
moc.saveRecursively()
return newItem!
}
## Get records from database
class func getOrders(moc:NSManagedObjectContext,postCompleted : (succeeded: Bool, result:[OrderTable]?) -> ()){
// 9911882342 dilip
// var arrayRecords = [OrderTable]()
let fetchRequest = NSFetchRequest();
moc.performBlockAndWait({
let entityDescription = NSEntityDescription.entityForName("OrderTable",inManagedObjectContext: moc)
fetchRequest.entity = entityDescription
do {
let resultOrders = try moc.executeFetchRequest(fetchRequest)as? [OrderTable]
postCompleted(succeeded:true,result: resultOrders );
} catch {
let fetchError = error as NSError
debugPrint(fetchError)
postCompleted(succeeded: false, result: nil)
}
})
}
}
##Controller class to get and load table from database values
//
// OrderOpenAndCloseViewController.swift
// POSApp
//
import Foundation
import UIKit
import CoreData
class OrderOpenAndCloseViewController: UIViewController{
@IBOutlet weak var tableViewOrderListing: UITableView!
var arrayExistingOrders = [OrderTable]() // stores existing orders
let coreDataStack = CoreDataStack() // use for multithreaded coredata
let viewControllerUtils = ViewControllerUtils();// use for activity indicator
//MARK: view Life cycle
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated);
// call method to get records from database
getOpenExistingOrders();
}
//MARK: get all open existing orders from database
func getOpenExistingOrders(){
viewControllerUtils.showActivityIndicator(self.view)
if let newPrivateQueueContext =
self.coreDataStack.newPrivateQueueContext(){ // create new NSmanagedObject context
// call getOrder method of OrderTable to get orders from database with the help of closure and assign that to arrayExistingOrders of type OrderTable
OrderTable.getOrders(newPrivateQueueContext, postCompleted: { (succeeded, result) in
self.arrayExistingOrders = result!
let item = self.arrayExistingOrders.last // for value check get last object and print orderNo from that
print("order no =%@",item?.orderNo)// prints here value or in loop also 1000-001 etc
self.tableViewOrderListing.reloadData()
self.viewControllerUtils.hideActivityIndicator(self.view) // hide loader
})
}
}
}
//MARK: tableview datasource methods
extension OrderOpenAndCloseViewController: UITableViewDataSource, UITableViewDelegate{
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayExistingOrders.count // return number of orders
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("OrderOpenAndCloseCell", forIndexPath: indexPath)as? OrderOpenAndCloseCell
let item = arrayExistingOrders[indexPath.item]
print("orderNo =%@",item.orderNo) //here prints orderNo =%@ nil instead of value order no =%@ Optional("1000-001") etc
let orderNo = item.orderNo
var totalOrderCost:String?
if let totalcost = item.totalPrice{
totalOrderCost = totalcost
}else{
totalOrderCost = ""
}
let serverName = item.server
let openedDate = item.openedDate
cell?.labelOrderNo.text = orderNo;
cell?.labelServerName.text = serverName;
cell?.labelOpenedDate.text = openedDate
cell?.labelTotalPrice.text = totalOrderCost
return cell!;
}
}
Upvotes: 2
Views: 206
Reputation: 70966
Your problem is in this line:
if let newPrivateQueueContext =
self.coreDataStack.newPrivateQueueContext
You then use newPrivateQueueContext
to perform the fetch. Then you let newPrivateContext
go out of scope, which causes it to be deallocated.
When you fetch a managed object, that managed object needs its managed object context, but it does not keep a strong reference to it. If the managed object context is deallocated, any managed objects that have been fetched from it are now useless. You can print results while the context still exists but as soon as you let it be deallocated you can't use the results any more.
You need to keep a strong reference to the context that you use for fetching, for as long as you need to use the results of the fetch. That probably means making it a property of your view controller, but there are many ways to do that.
Upvotes: 1