swift - 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
在运行时显示以下消息:
我希望有一个人可以帮助我 :/
解决方案
与那里相同: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
}
}
}
我个人不喜欢最后一个解决方案,但我无法找到另一种解决方法
推荐阅读
- flutter - Flutter WebView 插件在 iOS 14+ 上安装时会导致应用崩溃
- c++ - 需要遍历整个对象,除了前两个元素。有设计模式吗?
- tableau-api - 如何通过表格中的参数字段设置过滤器值?
- python - 如何将值列表添加到嵌套字典列表中?
- reactjs - 在 react-native 中添加表单验证,删除多余的空格
- visual-c++ - C++ 如何使用 TinyExpr 解析字符串中的数学问题?
- docker - 为什么不通过仅在 docker-compose 中绑定卷来安装模块
- neo4j - neo4j:包含特定关系的最短路径
- kubernetes - 入口控制器本地集群
- spring - Tomcat 中的 LTPA 令牌(Spring 安全性)