【未解決】SceneViewを使うと画面がピンクになる。。。かもしれない(Swift)
はじめに
先日、下記のいつでもどこでもサイコロをふれるアプリをリリースしたのですが一部のユーザーから「画面がピンクになってなにも表示されない!」という報告がありました。
いろいろ調べたのですが今のところ実装側でできる対策がないので OS のアップデートで修正されるのを祈るだけです。
開発環境
- Xcode 14.3
使ったもの
- SwiftUI
- SceneKit
現象
本来であれば左のようにサイコロが表示されるのですが右のようにピンク(紫?)画面が表示されるそうです(手元では再現していないので画像はイメージです)。 SceneView
の表示部分がピンク色になっているようです。
本来 | バグ |
---|---|
今のところ報告を受けている端末はすべて iPhone 14 Pro(iOS 16.5.1)です。ただ iPhone 14 Pro(iOS 16.5.1)でも正常に表示されている方もいるようです。
調査
アプリではピンク色を設定している箇所はなかったのでまったく検討もつかなかったのですがシェーダー?関連のエラーでこの表示になるそうです。
Unity ではたまに起こるそうなのですが今回は SceneKit を使っておりとくに特殊な設定はしていないつもりです。
Google で「iPhone pink screen」と検索するといくつかヒットするのでもしかしたら iPhone ではたまにあることなのかも?
やってみたこと
元のコードはざっくりこんな感じでした。
import SwiftUI
import SceneKit
struct ContentView: View {
var body: some View {
NavigationStack {
NavigationLink {
HogeView()
} label: {
Text("hoge")
}
}
}
}
final class HogeScene: SCNScene {
override init() {
super.init()
let cameraNode: SCNNode = {
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: -0.35, y: 2, z: 6)
cameraNode.rotation = .init(x: 1, y: 0, z: 0, w: -Float.pi/8)
return cameraNode
}()
rootNode.addChildNode(cameraNode)
let floorNode: SCNNode = {
let floor = SCNFloor()
floor.reflectivity = 0.1
floor.firstMaterial?.diffuse.contents = UIColor.systemBlue
let floorNode = SCNNode(geometry: floor)
floorNode.name = "floor"
floorNode.physicsBody = SCNPhysicsBody(type: .static, shape: .init(geometry: floor))
return floorNode
}()
rootNode.addChildNode(floorNode)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
struct HogeView: View {
private let scene = HogeScene()
var body: some View {
VStack {
SceneView(scene: scene)
}
}
}
やってみたことは下記2つです。
-
SCNScene
のサブクラス化をやめる -
scene
に@StateObject
をつける
SCNScene
のサブクラス化をやめる
SCNScene
のサブクラス化はよくないというのをみかけたので HogeScene
はやめて下記のように HogeView
の init で add するように修正してみました。
struct HogeView: View {
private let scene = SCNScene()
var body: some View {
VStack {
SceneView(scene: scene)
}
}
init() {
let cameraNode: SCNNode = {
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
cameraNode.position = SCNVector3(x: -0.35, y: 2, z: 6)
cameraNode.rotation = .init(x: 1, y: 0, z: 0, w: -Float.pi/8)
return cameraNode
}()
scene.rootNode.addChildNode(cameraNode)
let floorNode: SCNNode = {
let floor = SCNFloor()
floor.reflectivity = 0.1
floor.firstMaterial?.diffuse.contents = UIColor.systemBlue
let floorNode = SCNNode(geometry: floor)
floorNode.name = "floor"
floorNode.physicsBody = SCNPhysicsBody(type: .static, shape: .init(geometry: floor))
return floorNode
}()
scene.rootNode.addChildNode(floorNode)
}
}
とくに変化なしでした。
scene
に @StateObject
をつける
上記のコードだと Scene の init が何回も呼ばれるのでよくないのでは?というアドバイスをもらったので下記修正をしてみました。
+ final class HogeScene: SCNScene, ObservableObject {
- final class HogeScene: SCNScene {
+ @StateObject private var scene = HogeScene()
- private let scene = HogeScene()
無駄に init が呼ばれることはなくなりましたがピンク表示は解決しませんでした。
おわりに
結局ピンク画面になる解決策はわかりませんでした。手元で再現しないのでなかなか調査もできず、同機種・同 OS でも起こらないこともあるようでもうお手上げです🙌
SwiftUI と SceneKit の組み合わせがだめなのか UIKit にすれば解決するのか謎は深まるばかりです。
もしピンク画面になった方がいれば機種名と OS バージョンを教えていただけるとありがたいです。
2023/10/16追記
Xcode 15 でビルドしてアプリをアップデートしたところピンク表示になっていた方も表示されるようになったとの報告がありました。
Xcode が原因か iOS が原因かはわかりませんがとりあえず表示されるようになってよかったです😌
Discussion