kaushal
kaushal

Reputation: 911

Coredata managedObject issue swift

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

Answers (1)

Tom Harrington
Tom Harrington

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

Related Questions