1

In the following code:

public class  Foo {
    
    public func createNode() -> SCNNode {
        return SCNNode()
    }

    public func createNode() -> SKNode {
        return SKNode()
    }
}

Compiling with Swift 6 strict concurrency checking, the line return SKNode() doesn't compile with the error Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context and the proposed fix Add '@MainActor' to make instance method 'createNode()' part of global actor 'MainActor'.

Any call to a SKNode method or property does the same.

This doesn't happen with the return SCNNode().

In my app, these methods should be called inside my SCNSceneRendererDelegate methods, such as renderer(_:updateAtTime:), so I can't take the penalty of going back to the MainActor.

Why is SKNode bound to MainActor (when SCNNode is not), and how to walk this around ?

4
  • 4
    SKNode is a subclass of UIResponder, and UIResponder is isolated to the main actor, so SKNode is, too. Commented May 26, 2024 at 19:17
  • 2
    See Getting Started with Nodes: Ensure Node Access on the Main Thread. They are explicit that you must do this on the main thread (justifying the isolation to the main actor). Commented May 26, 2024 at 19:34
  • Whereas an SCNNode is just a mathematical construct. Basically you are equivocating over the word the "node". And what is "the penalty of going back to the MainActor" supposed to mean? Commented May 26, 2024 at 19:35
  • Ok understood. Thanks a lot for the explanation and the reference. If you make that an answer I’ll accept it. Commented May 26, 2024 at 21:28

1 Answer 1

3

SKNode is a subclass of UIResponder, and UIResponder is isolated to the main actor, so SKNode is, too.

Also see Getting Started with Nodes: Ensure Node Access on the Main Thread. They are explicit that you must do this on the main thread (justifying the isolation to the main actor).

To resolve this, you can probably solve this by isolating createNode to the main actor, e.g.,

@MainActor
public func createNode() -> SKNode {…}

And, because SKNode is not Sendable, this createNode must be called from a context that is also isolated to the main actor, too. Or, if Foo warrants it, perhaps isolate the whole type to the main actor, too. It’s hard to be specific without seeing more of the Foo implementation, how you’re ensuring the thread-safety of that, etc. But hopefully this is enough to get you going.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.