-1

I have a carousel and each carousel item contains a unique tableview. When you tap the add button it takes you to a new view controller so that you can give the tableview a name and associate items to display in each cell. Now when I hit the save button it performs the segue back to the carousel's viewcontroller. My prepareforsegue looks like this:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    let destinationVC = segue.destination as! BillSplittersViewController
    let passedBill: NSManagedObject = bill as NSManagedObject

    destinationVC.allBillSplitters = getUpdatedSplitters()
    print(2)            
    print(destinationVC.allBillSplitters)
    destinationVC.billName = billName
    destinationVC.bill = passedBill
}

When the carousel view controller is displayed it doesn't show the added item in the carousel which loads from the allBillSplitters array. If I try reloading the carousel in viewdidload, viewwillappear or view willlayoutsubviews nothing changes. It does update if I do it in viewdidlayoutsubviews but you can see this happening which isn't great.

To debug I tried printing the array in prepareforsegue and then in viewdidload and it prints the array in prepareforsegue without the added item and the does the same thing in viewdidload -- but then it prints them again with the added item -- but I can't see it in the loaded view.

I'm using iCarousel if that helps. I am new to this and unsure what's going on so I don't know what code to use. I am using storyboards for both viewcontrollers and the segue is attached to the view and not the button itself. Any help would be great. Thanks!

More information:

@IBAction func saveButtonWasPressed() {

    let managedContext = bill.managedObjectContext

    if let splitter = splitter {
        splitter.mutableSetValue(forKey: "items").removeAllObjects()
        setBillSplitterValues(splitter)
        setSelectedItemsToBillSplitter(splitter)
    } else {
        let entity =  NSEntityDescription.entity(forEntityName: "BillSplitter", in: managedContext!)
        let newBillSplitter = NSManagedObject(entity: entity!, insertInto: managedContext)

        setBillSplitterValues(newBillSplitter)
        setSelectedItemsToBillSplitter(newBillSplitter)
    }

    do {
        try managedContext!.save()
    }
    catch let error as NSError {
        print("Core Data save failed: \(error)")
    }

    self.performSegue(withIdentifier: "segueToBillSplitters", sender: self)
}

retrieving the new billSplitters:

func getUpdatedSplitters() -> [BillSplitter] {
    var allBillSplitters = [BillSplitter]()

    let managedContext = bill.managedObjectContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "BillSplitter")
    let predicate = NSPredicate(format: "ANY bills == %@", bill)

    fetchRequest.predicate = predicate

    do {
        let results =
            try managedContext!.fetch(fetchRequest)
        allBillSplitters = results as! [BillSplitter]
    } catch let error as NSError {
        print("Could not fetch \(error), \(error.userInfo)")
    }
    return allBillSplitters
}

So when pressing save, it either updates an existing 'billSplitter' to coredata or adds a new one, then calls performSegue. In prepareForSegue it then fetches all the 'billSplitters' from CoreData and passes them to the destination view controller.

I thought a NSManagedObjectContextDidSave observer might help if it called performSegue once the notification was received but nothing changed.

Update:

I have tried the following in my saveButtonWasPressed method. When the viewcontroller loads, it quickly shows the old carousel then flickers and shows the updated carousel. I'm not sure where to go from here.

@IBAction func saveButtonWasPressed() {

    DispatchQueue.global(qos: .background).async { [weak weakSelf = self] in
        let managedContext = weakSelf?.bill.managedObjectContext

        if let splitter = weakSelf?.splitter {
            splitter.mutableSetValue(forKey: "items").removeAllObjects()
            weakSelf?.setBillSplitterValues(splitter)
            weakSelf?.setSelectedItemsToBillSplitter(splitter)
        } else {
            let entity =  NSEntityDescription.entity(forEntityName: "BillSplitter", in: managedContext!)
            let newBillSplitter = NSManagedObject(entity: entity!, insertInto: managedContext)

            weakSelf?.setBillSplitterValues(newBillSplitter)
            weakSelf?.setSelectedItemsToBillSplitter(newBillSplitter)
        }

        do {
            try managedContext!.save()
        }
        catch let error as NSError {
            print("Core Data save failed: \(error)")
        }

        DispatchQueue.main.async { [weak weakSelf = self] in
            guard let weakSelf = weakSelf else { return }
            weakSelf.performSegue(withIdentifier: "segueToBillSplitters", sender: self)
        }
    }

}
Mozahler
  • 4,958
  • 6
  • 36
  • 56
Wazza
  • 1,725
  • 2
  • 17
  • 49
  • Have you tried `tableView.reloadData()` on the table view where the data is changing? – faircloud Jan 30 '17 at 16:24
  • It's not the tableviews I'm having an issue with, its the carousel they are in. And reloading the carousel doesnt work. – Wazza Jan 30 '17 at 17:03
  • It would help if you could post the rest of the relevant code. The UI not updating might be easily fixed by using GCD library to dispatch the UI update to the main thread and/or dispatch other work off the main thread to prevent it from being blocked – MikeG Jan 30 '17 at 19:38
  • @MikeG apologies, I had no idea what would help. I've added more. I've never had to use the GCD library or dispatch before, so any hints would be great. I will google it as always. Thanks for your help – Wazza Jan 31 '17 at 13:54

1 Answers1

0

I may not understand what you are asking exactly but my only input is that when I use prepare for segue I always use a segue identifier

 var valueToPass
 override func prepare(for segue: UIStoryboardSegue, sender: Any?){
    if (segue.identifier == "yourSegue") {
        let viewController = segue.destination as! ViewController
        viewController.passedValue = valueToPass as String
 }

Your declare your identifier in the storyboard, also make sure your segue is an action segue

Jarad Kears
  • 114
  • 2
  • 11