首页 > 解决方案 > Apple ARKit 人脸识别项目 (ARKitFaceExample) 的运行时问题

问题描述

苹果发布了这个:

https://developer.apple.com/documentation/arkit/creating_face-based_ar_experiences

不久前。我试过了,它会产生运行时问题。

我正在使用 iPhone XR,该项目正在成功构建并且工作正常。但是至少应该在主线程中执行一个进程,但我无法弄清楚这是哪一部分:/

错误消息看起来像

2019-04-26 20:17:40.360763+0200 ARKitFaceExample[16979:3438178] [DYMTLInitPlatform] platform initialization successful
2019-04-26 20:17:40.551196+0200 ARKitFaceExample[16979:3438133] Metal GPU Frame Capture Enabled
2019-04-26 20:17:40.551498+0200 ARKitFaceExample[16979:3438133] Metal API Validation Enabled
2019-04-26 20:17:40.710761+0200 ARKitFaceExample[16979:3438133] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2019-04-26 20:17:40.711381+0200 ARKitFaceExample[16979:3438133] [MC] Reading from public effective user settings.
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState]
PID: 16979, TID: 3438188, Thread name: com.apple.CoreMotion.MotionThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 0
Backtrace:
4   libobjc.A.dylib                     0x000000021789f6f4 <redacted> + 56
5   CoreMotion                          0x000000021dfe9638 CoreMotion + 292408
6   CoreMotion                          0x000000021dfe9b68 CoreMotion + 293736
7   CoreMotion                          0x000000021dfe9a78 CoreMotion + 293496
8   CoreMotion                          0x000000021e0178a8 CoreMotion + 481448
9   CoreMotion                          0x000000021e0178ec CoreMotion + 481516
10  CoreFoundation                      0x000000021862b78c <redacted> + 28
11  CoreFoundation                      0x000000021862b074 <redacted> + 276
12  CoreFoundation                      0x0000000218626368 <redacted> + 2276
13  CoreFoundation                      0x0000000218625764 CFRunLoopRunSpecific + 452
14  CoreFoundation                      0x0000000218626498 CFRunLoopRun + 84
15  CoreMotion                          0x000000021e017280 CoreMotion + 479872
16  libsystem_pthread.dylib             0x00000002182a5920 <redacted> + 132
17  libsystem_pthread.dylib             0x00000002182a587c _pthread_start + 48
18  libsystem_pthread.dylib             0x00000002182addcc thread_start + 4
2019-04-26 20:17:40.745827+0200 ARKitFaceExample[16979:3438188] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication applicationState]
PID: 16979, TID: 3438188, Thread name: com.apple.CoreMotion.MotionThread, Queue name: com.apple.root.default-qos.overcommit, QoS: 0
Backtrace:
4   libobjc.A.dylib                     0x000000021789f6f4 <redacted> + 56
5   CoreMotion                          0x000000021dfe9638 CoreMotion + 292408
6   CoreMotion                          0x000000021dfe9b68 CoreMotion + 293736
7   CoreMotion                          0x000000021dfe9a78 CoreMotion + 293496
8   CoreMotion                          0x000000021e0178a8 CoreMotion + 481448
9   CoreMotion                          0x000000021e0178ec CoreMotion + 481516
10  CoreFoundation                      0x000000021862b78c <redacted> + 28
11  CoreFoundation                      0x000000021862b074 <redacted> + 276
12  CoreFoundation                      0x0000000218626368 <redacted> + 2276
13  CoreFoundation                      0x0000000218625764 CFRunLoopRunSpecific + 452
14  CoreFoundation                      0x0000000218626498 CFRunLoopRun + 84
15  CoreMotion                          0x000000021e017280 CoreMotion + 479872
16  libsystem_pthread.dylib             0x00000002182a5920 <redacted> + 132
17  libsystem_pthread.dylib             0x00000002182a587c _pthread_start + 48
18  libsystem_pthread.dylib             0x00000002182addcc thread_start + 4
2019-04-26 20:17:52.404466+0200 ARKitFaceExample[16979:3438187] [SceneKit] Error: Scene <SCNScene: 0x283b7a260> is modified within a rendering callback of another scene (<SCNScene: 0x283b68000>). This is not allowed and may lead to crash

运行时显示以下消息:

我希望有一个人可以帮助我 :/

运行时消息

标签: swiftscenekitaugmented-realityarkitswift5

解决方案


与那里相同:ARKit 模板 Xcode 项目 Main Thread Checker 日志控制台

因为是我的回答,所以我也贴在这里。

(当然您可以禁用检查器,但有时它会有所帮助。请查看https://stackoverflow.com/a/45689250/7183675​​了解此内容。)

错误在 Apple 框架内,所以我发现解决它的唯一方法是子类化 UIApplication 类并以这种方式检查主线程上的应用程序状态:

1) 用这些行添加 main.swift 文件(这个名字真的很重要!)

import UIKit

    UIApplicationMain(
        CommandLine.argc,
        CommandLine.unsafeArgv,
        NSStringFromClass(MyApplicationClass.self),
        NSStringFromClass(MyDelegateClass.self)
    )

2)如果它在那里,或者项目由于多个入口点而无法编译,@UIApplicationMain请删除MyDelegateClass

3) 在 MyApplicationClass.swift 中添加:

    import UIKit

    class MyApplicationClass: UIApplication {
    let semaphore = DispatchSemaphore(value: 0)
    override var applicationState: UIApplication.State {
        if Thread.current == Thread.main {
            return super.applicationState
        }

        var toReturn =  UIApplication.State.inactive

        DispatchQueue.main.async { [weak self] in
            guard let self = self else {return}
            toReturn = self.superAppState()
            self.semaphore.signal()
        }
        semaphore.wait()
        return toReturn
    }

    private func superAppState() -> UIApplication.State {
        return super.applicationState
    }
}

现在您在主线程上调用 UIApplication.applicationState ,因此不会发生问题。

好吧,还有一个问题。如果 CMMotionManager 是从主线程初始化的,那么 if 将阻塞主线程并等待 UIApplication.State。这意味着僵局。在这种情况下,您无法设置信号量。返回可信状态避免死锁的唯一方法是以这种方式实现应用程序状态:

4)

import UIKit

        class MyApplicationClass: UIApplication {

    private static var configured = false

    private var state = UIApplication.State.inactive

    override var applicationState: UIApplication.State {
        if !MyApplicationClass.configured {
            MyApplicationClass.configured = true
            NotificationCenter.default.addObserver(self, selector: #selector(setStatus(_:)), name: UIApplication.didBecomeActiveNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(setStatus(_:)), name: UIApplication.willResignActiveNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(setStatus(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
            NotificationCenter.default.addObserver(self, selector: #selector(setStatus(_:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
        }
        if Thread.current == Thread.main {
            return super.applicationState
        }
        return state
    }

    @objc func setStatus(_ notif: Notification) {
        switch notif.name {
        case UIApplication.didBecomeActiveNotification:
            state = .active
        case UIApplication.willResignActiveNotification:
            state = .inactive
        case UIApplication.willEnterForegroundNotification:
            state = .background
        case UIApplication.didEnterBackgroundNotification:
            state = .background
        default:
            state = .inactive
        }
    }
}

我个人不喜欢最后一个解决方案,但我无法找到另一种解决方法


推荐阅读