I am trying to use a SKView
in my login UI for some animations. The SKView
is added as a subview to a LoginContainerView
as well as the view containing the UITextFields and the sign in button. All of the subviews are positioned with autolayout and the FireScene
attached to the SKView
has it's scaleMode set to .resizeFill
.
The issue I'm having is very clear to observe from this clip: https://streamable.com/5it17 .
Clip explanation: Whenever I double tap any of the UITextFields (to trigger the UIMenuController / Paste button) the
FireScene
freezes for a brief amount of time (yet it's very noticeable) and the FPS drops down to around 30 for 1-2 seconds.
The only node that the FireScene
has added as its child node is a modified fireflies SKEmitterNode template. I'm fairly certain that this has nothing to do with the actual code (as it is very straightforward and concise) and is probably a UIKit mixed with SpriteKit bug.
Relevant code:
class FireScene: SKScene {
// MARK: - Properties
var fireSparkEmitter: SKEmitterNode? = nil
// MARK: - Inherited
override func didChangeSize(_ oldSize: CGSize) {
// position the emitter to scene's center
fireSparkEmitter?.position = CGPoint(x: size.width/2, y: size.height/2)
}
override func didMove(to view: SKView) {
if let emitter = fireSparkEmitter {
emitter.resetSimulation()
} else {
guard let emitter = SKEmitterNode(fileNamed: "FireSparks.sks") else { return }
addChild(emitter)
fireSparkEmitter = emitter
}
}
}
class LoginContainerView: UIView {
/// ...
let fireBackgroundScene: FireScene = {
let scene = FireScene(size: .zero)
scene.scaleMode = .resizeFill
return scene
}()
/// ...
// MARK: - Inherited
// called after view initialization
func setupSubviews() {
let skView = SKView(frame: .zero)
skView.translatesAutoresizingMaskIntoConstraints = false
addSubview(skView)
skView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
skView.topAnchor.constraint(equalTo: topAnchor).isActive = true
skView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
skView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
skView.showsFPS = true
skView.presentScene(fireBackgroundScene)
}
}
PS: I've tried to profile the app with Time Profiler and it seems that the bottleneck is the UITextField gesture handling by UIKit itself.
Your issue seems related to a different layout syncronization between SKView
and the other UIKit
objects.
SKView
have a property called isAsynchronous (default = true) that indicates
whether the content is rendered asynchronously.
You can try to set:
skView.isAsynchronous = false
to syncronize your SKView
with the core animation updates.
This could be not enough because you'll syncronize SKView
with the Core Animations of your project but there are always the UIKit-style animations that could be out of sync.
If this property don't solve your issue you can change also the preferredFramesPerSecond property. Remember that when you try to mix two frameworks (sprite-kit
and UIKit
) you will inevitably incur to unpleasant hitches.