I have posted several times asking for help to resolve a conundrum involving the ability to invoke "needsDisplay = true" from a different class. I have done some tests and seem to have revealed some inconsistent behavior in Swift which I don't understand. As I said in previous posts, for some reason I haven't acquired a deep understanding of Apple's object oriented programming - my brain somehow can't wrap itself around a number of its concepts.
First, here is an outline of the class structure of my Mac app, leaving out unimportant details:
class GameViewController: NSViewController { @IBOutlet weak var graph: GraphView! @IBAction func h1_Slider(_ sender: NSSlider) { h1_length = sender.floatValue dodraw() // This is only here to make a point about - it is not used normally } func dodraw() { graph.needsDisplay = true return } <lots of other stuff to set up Metal drawing> } class Renderer: NSObject, MTKViewDelegate { public var graphRef = GameViewController() //. Allows access to GameViewController from elsewhere <lots of stuff to set up Metal> func draw(in view: MTKView) { // Metal drawing loop grafRef.dodraw() // this is supposed to cause GraphView to update its drawing <this is where the Metal drawing is done> } } class GraphView:NSView { override func draw(_ dirtyRect:CGRect) { <This is where the Bezier drawing takes place in a View in the Storyboard View identified as an instance of GraphView } }
Basically, the inner loop of the Metal drawing, which occurs 60 times a second, calls the dodraw() method in the GameViewController via the reference graphRef. This should set the needsDisplay Bool to true in GraphView so that the graph can be drawn. Instead I get "Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value" with the graph underlined in red.
Here is the inconsistency, as I see it. If I replace the "needsDisplay = true" in the dodraw() method with a print("Q") and do nothing else, the letter Q is printed many times in the output window of Xcode. This shows that the graphRef link in Renderer is working fine. Likewise, if I put back the "graph.needsDisplay = true" and remove the dodraw() call in the Metal drawing loop, the graph is displayed while I move the slider in the GameViewController class. This shows that there seems to be no trouble unwrapping the Optional value in the "graph.needsDisplay = true" statement.
I consider this to be a very inconsistent behavior: I have no trouble invoking the needsDisplay = true command by appending a "graph." before it and I have no trouble referring to the dodraw() method from the Metal inner loop. Only trouble is I can't do these at the same time. What is going wrong? Is it a misconception about how Swift works?