I must be making some silly mistake, but I don’t have any clue what. Hopefully you’ve got an idea?
I am trying to implement this method on a custom delegate class (I think I wouldn’t have to use a separate delegate but try to reduce possible other errors):
In the delegate classptr, I use this:
methods.Append new TargetClassMethodHelper("renderer:updateAtTime:", AddressOf impl_rendererUpdateAtTime, "v@:@d")
And the implementation takes the following parameters:
pid as ptr, sel as ptr, renderer as ptr, attime as double
Finally I attach this object to a SCNView’s delegate property and keep it alive in a shared class dictionary.
When I try to run this, I don’t get any “unknown selector” error like usual but instead a StackOverflow exception with the following thread crash:
[quote]Thread 8 Crashed:: Dispatch queue: com.apple.scenekit.renderingQueue.SCNView0xc316f80
0 libsystem_kernel.dylib 0x02e1269a __pthread_kill + 10
1 libsystem_pthread.dylib 0x02e40f19 pthread_kill + 101
2 libsystem_sim_c.dylib 0x02bcaa5a abort + 156
3 libsystem_sim_c.dylib 0x02b93b89 __assert_rtn + 399
4 rbframework.dylib 0x002963b5 0x23f000 + 357301
5 com.codeservice.rdscontrols 0x0017e9b5 iOSLibSceneRendererDelegate.!impl_rendererUpdateAtTime%%pppf8 + 307
6 com.apple.SceneKit 0x026ffab3 -[SCNRenderer _update:rendererContext:] + 544
7 com.apple.SceneKit 0x02700215 -[SCNRenderer _draw] + 585
8 com.apple.SceneKit 0x02762cbb -[SCNView _drawAtTime:] + 555
9 com.apple.SceneKit 0x02764129 __23-[SCNView _displayLink]_block_invoke + 93
10 com.apple.SceneKit 0x0273285f __49-[SCNDisplayLink _callbackWithTime:andDeltaTime:]_block_invoke + 102
11 libdispatch.dylib 0x02ae4a2a _dispatch_call_block_and_release + 15
12 libdispatch.dylib 0x02b0103f _dispatch_client_callout + 14
13 libdispatch.dylib 0x02ae9cbd _dispatch_queue_drain + 689
14 libdispatch.dylib 0x02ae98ac _dispatch_queue_invoke + 197
15 libdispatch.dylib 0x02aeb9e7 _dispatch_root_queue_drain + 367
16 libdispatch.dylib 0x02aeb7b3 _dispatch_worker_thread + 92
17 libsystem_pthread.dylib 0x02e3ee13 _pthread_body + 138
18 libsystem_pthread.dylib 0x02e3ed89 _pthread_start + 162
19 libsystem_pthread.dylib 0x02e3ce52 thread_start + 34
Do I have to tell the delegate class it confirms to the SCNSceneRendererDelegate protocol? Must the delegate be based on SCNRenderer instead of NSObject? Or what is the real problem?
Your Xojo code is getting invoked from a non-Xojo thread.
For the crash, the problem is that the code is being run in a thread other than the main thread which Xojo doesn’t like and triggers a StackOverflowException for (or sometimes other exceptions, seemingly randomly). Basically the only way you will possibly (not always) be able to make this work in Xojo is to add
#Pragma StackOverflowChecking false
To the top of the impl_whatever method, explicitly retain every returned object and assign them to a variable in the class, then make a boolean variable that you monitor with a Xojo.Core.Timer.CallLater where you use the retained variables on the main thread in Xojo code. It’s clunky but I have gotten it to work before. Take a look at my AVFoundation.AVCaptureMetadataOutput class in iOSKit for a more concrete example and I’ll privately send you an example project in an hour or two.
Edit: You ninja edited the selector so I removed the now irrelevant part of my reply. Also <https://xojo.com/issue/40205> would remedy the situation so that crashes like you are seeing don’t happen.
Thanks, Joe and Jason!
And excellent there is a workaround! For cases like this: Shouldn’t it be possible to attach another method on the delegate “eventForwarder” or whatever that the first method calls with a performSelectorOnMainThread or similar function call?
(And sorry: I initially copied a wrong method description. Had it fixed but you’ve been faster )
EDIT: Excellent, Jason, it doesn’t crash anymore!
Yes, I have considered this and have a private partial implementation somewhere over here. I’ll send that to you as well in just a bit.
I just tried a bit myself and it seems like one is very limited to what can be done in a threaded implementation. Creating the object itself from pid: Bang! Creating an NSArray to forward something to the main thread method: Crash! System.DebugLog works
Doing anything from a non-Xojo thread is unsupported. At best you might be able to get lucky and only have code that calls out to the OS via declares and punt code back to the main thread via CFRunLoopTimer or something similar (which SceneKit may not be happy with).
Thanks, Joe. Phew, this is getting much more complicated than I thought. Especially because it’s a delegate than runs in the view update cycle of Scenekit, which means it is called at every frame and should be handled ASAP.
EDIT: But sometimes things look more frightening at first sight than they really are. Here’s how I could solve it without the need for a class timer who checks for changes:
I installed a shared private Dictionary where I put the message or messageobject in, its key being pid.
Then I added a ExamineNotificationDict shared method to the delegate class
The delegate classptr was extended by
methods.Append new TargetClassMethodHelper("checkDict", AddressOf ExamineNotificationDict, "v@:")
and the impl_rendererUpdateAtTime code goes like
[code] #Pragma StackOverflowChecking false
NotificationDict.Value(pid) = attime
Declare sub performSelectorOnMainThread lib FoundationLib selector “performSelectorOnMainThread:withObject:waitUntilDone:” _
(id as ptr, aselector as Ptr, withObject as Ptr, waituntildone as boolean)
performSelectorOnMainThread pid, NSSelectorFromString(“checkDict”), Nil, false
#Pragma Unused Sel
#Pragma Unused renderer[/code]
Not the best of all possible solutions, but the delay seems to be acceptable.