我创建了SCNNode
的子类。它由几个子节点组成。
我已经声明了一种方法,即。 soundCasual()
将SCNAudioPlayer
添加到此类的实例。调用此方法时,一切都按预期工作并且正在播放音频。每当该节点被点击(手势)时,就会在该节点上调用此方法。
代码:
class MyNode: SCNNode {
let wrapperNode = SCNNode()
let audioSource5 = SCNAudioSource(fileNamed: "audiofile.mp3")
override init() {
super.init()
if let virtualScene = SCNScene(named: "MyNode.scn", inDirectory: "Assets.scnassets/Shapes/MyNode") {
for child in virtualScene.rootNode.childNodes {
wrapperNode.addChildNode(child)
}
}
}
func soundCasual() {
DispatchQueue.global(qos: .userInteractive).async { [weak self] in
if let audioSource = self?.audioSource5 {
let audioPlayer = SCNAudioPlayer(source: audioSource)
self?.wrapperNode.removeAllAudioPlayers()
self?.wrapperNode.addAudioPlayer(audioPlayer)
}
}
}
}
仪器内的问题(分配)
当我分析整个代码库(还有其他几件事)时,我发现只要在该节点上点击,在Instruments中进行性能分析时,SCNAudioPlayer的分配计数就会增加一。但是所有增加都是持续。根据{{1}}的定义,我假设播放器在播放后被删除了,这就是为什么增量应该在瞬时分配中的原因,但是它不能像这样工作。这就是为什么我在将SCNAudioPlayer添加到节点之前尝试SCNAudioPlayer
的原因,如您在removeAllAudioPlayers()
的代码中所见。但是问题仍然存在。
直到拍摄此快照为止,我在该节点上轻击了 17 次,并且还针对SCNAudioPlayer的持久分配显示了17个。
注意 :soundCasual()
应该是10,因为我正在应用中使用10个音频源
这对于我的应用程序中的所有其他SCNNode都是如此。 请帮助,因为我无法理解我到底想念什么。
编辑
按照建议,我将SCNAudioSource
更改为
init()
尽管如此,“乐器”中的分配将audioPlayers显示为持久性的。尽管在检查let path = Bundle.main.path(forResource: "Keemo", ofType: "scn", inDirectory: "Assets.scnassets/Shapes/Keemo")
if let path = path , let keemo = SCNReferenceNode(url: URL(fileURLWithPath: path)) {
keemo.load()
}
func soundPlay() {
DispatchQueue.global(qos: .userInteractive).async { [weak self] in
if let audioSource = self?.audioSourcePlay {
audioSource.volume = 0.1
let audioPlayer = SCNAudioPlayer(source: audioSource)
self?.removeAllAudioPlayers()
self?.addAudioPlayer(audioPlayer)
}
}
}
时它表明在某一点上仅附加了一个audioPlayer节点。
编辑
即使在简单情况下,当我使用默认情况下在XCode中创建的Scenekit应用程序中附加的样板代码库时,也会出现此问题。因此,此问题已作为Apple的错误提出。 https://bugreport.apple.com/web/?problemID=43482539
WORKAROUND
我使用的是AVAudioPlayer而不是SCNAudioPlayer,但不完全相同,但是至少这种方式的内存不会导致崩溃。
答案 0 :(得分:1)
我对SceneKit不熟悉,但是根据我对UIKit和SpriteKit的经验,我怀疑您对wrapperNode
和virtualScene
的使用会弄乱垃圾收集器。
我会尝试删除wrapperNode
并将所有内容添加到self
(因为self
是SCNNode
)。
您的场景中使用了哪个节点? self
还是wrapperNode
?并且您的示例代码wrapperNode
并未添加到self
中,因此它实际上可能不是场景的一部分。
此外,您可能应该使用SCNReferenceNode
而不是使用的虚拟场景。
!!!此代码未经测试!!!
class MyNode: SCNReferenceNode {
let audioSource5 = SCNAudioSource(fileNamed: "audiofile.mp3")
func soundCasual() {
DispatchQueue.global(qos: .userInteractive).async { [weak self] in
if let audioSource = self?.audioSource5 {
let audioPlayer = SCNAudioPlayer(source: audioSource)
self?.removeAllAudioPlayers()
self?.addAudioPlayer(audioPlayer)
}
}
}
}
// If you programmatically create this node, you'll have to call .load() on it
let referenceNode = SCNReferenceNode(URL: referenceURL)
referenceNode.load()
HtH!
答案 1 :(得分:0)
如果尚未找到答案,则需要在节点完成播放后从节点中删除SCNAudioPlayer:
if let audioSource = self?.audioSourcePlay {
audioSource.volume = 0.1
let audioPlayer = SCNAudioPlayer(source: audioSource)
self?.removeAllAudioPlayers()
self?.addAudioPlayer(audioPlayer)
self?.audioplayer.didFinishPlayback = {
self?.removeAudioPlayer(audioPlayer)
}
}