0

In order to obtain values from a previous viewController, I use a didSet on a structure.

class ReviewViewController:  UIViewController, UITextFieldDelegate {
var detailBuilding: Building? {
    didSet {
        configureView()
    }

}

override func viewDidLoad() {
    super.viewDidLoad()
    configureView()
    CKContainer.default()

}

override func viewWillAppear(_ animated: Bool) {
    print("this override ran")
    navigationItem.hidesBackButton = false

}

func configureView() {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "RatingAttributes")
    print("the buildingID is \(String(describing: detailBuilding?.buildingID))")

    request.predicate = NSPredicate(format: "buildingID == %@", String(describing: detailBuilding?.buildingID))
    print("configuration ran")
    do {
        let result = try context.fetch(request)
        //assert(result.count < 2)
        //print("the result we got was \(result[0])")
        for data in result as! [NSManagedObject] {
            print("The data was \(data.value(forKey: "buildingID")) ")
        }
    } catch {

        print("Failed to retreive core data")
    }
}

}

However, using print statements in the func configureView(), I am able to tell that the function runs 3 times. However, if I remove the call to configureView() from viewWillAppear(), then the view will not appear; if I remove it from didSet, then the values of detailBuilding (e.g detailBuilding.rating) will be nil. Though the third time the function runs, the values of detailBuilding are always nil anyway, meaning I can't use them.

In the previous viewController I have:

@objc func addReviewAction(_ sender: UIButton) {
    print("ran this correctly")
    //navigationController?.setNavigationBarHidden(true, animated: true)
    let controller = ReviewViewController()
    controller.detailBuilding = detailBuilding
    controller.navigationItem.title = ""
    navigationItem.hidesBackButton = true
    let backItem = UIBarButtonItem()
    backItem.title = ""
    backItem.tintColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
    navigationController?.navigationItem.backBarButtonItem = backItem
    navigationController?.pushViewController(ReviewViewController(), animated: true)

}

I have checked multiple times to make sure I am not accidentally calling configureView() from anywhere else.

My questions are: Why is configureView() running multiple times? Why is detailBuilding nil on the 3 rd out of 3 times. And should I be using a different method for acquiring detailBuilding, as I need the values it contains for my NSPredicate.

Thank you.

RufusV
  • 408
  • 3
  • 17
  • Set a breakpoint on your `configureView` method and look at the call stack and the instance's memory address each time it's called, that should give you the clues you need. – Gereon Feb 07 '19 at 20:47
  • @Gereon Thank you for the suggestion, I tried it and found that it runs the one in the didSet first. However, if I remove the call in the viewDidAppear, then the view won't load. But If I remove the call in the didSet, then t he detailBuilding values will all be nil, – RufusV Feb 07 '19 at 20:58

2 Answers2

2

You're creating two instances of ReviewViewController, and you set the detail only on one of them

// 1st instance
let controller = ReviewViewController() 
controller.detailBuilding = detailBuilding
controller.navigationItem.title = ""
navigationItem.hidesBackButton = true
let backItem = UIBarButtonItem()
backItem.title = ""
backItem.tintColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
navigationController?.navigationItem.backBarButtonItem = backItem

// 2nd instance, first is deallocated and never used.
navigationController?.pushViewController(ReviewViewController(), animated: true)
// replace with:
navigationController?.pushViewController(controller, animated: true)
Gereon
  • 17,258
  • 4
  • 42
  • 73
  • Thank you very much. After this I was also able to remove the call in the viewDidAppear method. – RufusV Feb 07 '19 at 21:22
1

From the code you just presented there should be only one two calls of configureView()

  1. made from didSet, right after the controller.detailBuilding = detailBuilding is executed.

  2. made from viewDidLoad after object initialization

That being said, you need to provide more code, especially:

viewWillAppear() from ReviewViewController and code that triggers displaying the ReviewViewController.

EDIT:

Thanks for more details :)

You have an issue in line: navigationController?.pushViewController(ReviewViewController(), animated: true)

it should be navigationController?.pushViewController(controller, animated: true)

That's why you've got nil. You are displaying a brand now ViewController not related to the one that have detailBuilding injected.

And that's why you've got 3 calls of configureView() method:

  1. viewDidLoad of controller of type ReviewViewController
  2. from injection (didSet)
  3. viewDidLoad of unnamed object of type ReviewViewController, with nothing injected, therfore with nil inside it's detailBuilding at 3rd call.
vol
  • 1,594
  • 11
  • 16