Post

Replies

Boosts

Views

Activity

Inconsistent behavior in invoking a Swift method from a different class?
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?
10
0
566
Aug ’23
draw in swift does not respond to needsDisplay = true
I am developing a Mac app in Swift which does graphics animations in two windows. One is a Metal window (MTKView) which works well. The other one plots a graph as a subclass of NSView and is connected to the Metal window using an outlet (which works). When I want to update the second window, I use "graph.needsDisplay = true", where graph is the name of the outlet. For some reason, the draw function does not execute when I use setNeedsDisplay in the MTKView class, whose draw command executes 60 times a second. I have verified that the draw function does work, since the graph is plotted when I resize the window, as it is supposed to do. I have a version of this program (written using Obj. C and OpenGL ES) for iOS which I wrote about 5 years ago and it works fine. The draw function is the exact equivalent of the code below (in Obj. C): class GraphView: NSView { override func draw(_ dirtyRect:NSRect) { super.draw(dirtyRect) var width:Float = 0.0, height:Float let backgroundColor = NSColor.cyan var iGraph, iData, i1:Int var x,y:Int backgroundColor.set() NSBezierPath.fill(bounds) height=Float(dirtyRect.size.height) width=Float(dirtyRect.size.width) let path=NSBezierPath() NSColor.black.setStroke() path.lineWidth = 0.5 path.move(to:NSPoint(x:0, y:Int(height)/2)) path.line(to:NSPoint(x:Int(width), y:Int(height)/2)) path.stroke() current+=1 if current>200 { current = 0 } points[current]=jz i1=current x = 0 y = Int(0.25*height*(1.0-points[i1]/height_vector)) path.move(to:NSPoint(x:0, y:Int(y))) for i in 0..<200 { x = i*Int(width/200.0) if i1<=0 {i1+=200} y = Int(0.5*height - 0.45*height*points[i1]/height_vector) path.line(to:NSPoint(x:x,y:y)) i1 -= 1 } path.stroke() } } Can anyone help? I have been trying everything under the sun and nothing works. I have been doing development of the Mac and iOS for more than 20 years, but, to be honest, have very little deep understanding of object oriented programming. I submitted a query on a similar question which was answered about 2 days ago. Thanks in advance.
11
0
780
Aug ’23
needsDisplay changes from true to false in Swift appkit
I am developing a Mac app in Swift which does graphics animations in two windows. One is a Metal window (MTKView) which works well. The other one plots a graph as a subclass of NSView and is connected to the Metal window using an outlet (which works). When I want to update the second window, I use "graph.needsDisplay = true", where graph is the name of the outlet. For some reason, the needsDisplay setting was being overridden: I set it equal to "true" and it was immediately set to "false", as I determined by printing the value. This was being done "behind my back" and is a complete mystery. Is there any reason why my setting would be overridden? Thanks!
2
0
331
Aug ’23
Filling vertex buffer using Swift and Metal
I am sure this is an elementary question, but I am new to Swift and Metal, but have a fair amount of experience using Objective C and OpenGL. I would like to render some mathematically generated surfaces in Metal and need to fill the vertex buffer with positions and normals. I would guess that creating a one dimensional array and adding to it using "append" is not the most efficient way to do this. The buffer might be quite large and I would like to set aside the memory for it in advance, which is how I did it using Objective C. Can anyone suggest the best way to do this? Thanks in advance.
1
0
318
Aug ’23