👌

【未解決】SceneViewを使うと画面がピンクになる。。。かもしれない(Swift)

2023/07/06に公開

はじめに

先日、下記のいつでもどこでもサイコロをふれるアプリをリリースしたのですが一部のユーザーから「画面がピンクになってなにも表示されない!」という報告がありました。

https://apps.apple.com/jp/app/id6450755473

いろいろ調べたのですが今のところ実装側でできる対策がないので OS のアップデートで修正されるのを祈るだけです。

開発環境

  • Xcode 14.3

使ったもの

  • SwiftUI
  • SceneKit

現象

本来であれば左のようにサイコロが表示されるのですが右のようにピンク(紫?)画面が表示されるそうです(手元では再現していないので画像はイメージです)。 SceneView の表示部分がピンク色になっているようです。

本来 バグ
normal error

今のところ報告を受けている端末はすべて iPhone 14 Pro(iOS 16.5.1)です。ただ iPhone 14 Pro(iOS 16.5.1)でも正常に表示されている方もいるようです。

調査

アプリではピンク色を設定している箇所はなかったのでまったく検討もつかなかったのですがシェーダー?関連のエラーでこの表示になるそうです。

参考:Application launched to a pink screen and a blank screen after built on Xcode and tested on Testflight

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