Я создал подкласс 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)
}
}
}
}
Проблема в инструментах (распределения)
Когда я анализирую всю свою кодовую базу (а это еще несколько вещей), я вижу, что всякий раз, когда я нажимаю на этот узел, счетчик выделения SCNAudioPlayer увеличивается на единицу при профилировании в инструментах. Но все увеличение составляет настойчивый. По определению SCNAudioPlayer я предполагал, что этот проигрыватель удаляется после воспроизведения, поэтому приращение должно быть в временных выделениях, но это не работает так. Вот почему я попробовал removeAllAudioPlayers() перед добавлением SCNAudioPlayer к узлу, как вы можете видеть в коде для soundCasual(). Но проблема остается.
Пока не был сделан этот снимок, я нажимал на этот узел примерно 17 раз, и он также показывает 17 против постоянных выделений для SCNAudioPlayer.
Примечание: SCNAudioSource - это 10, как и должно быть, поскольку я использую в приложении 10 источников звука.
И это в обязательном порядке происходит со всеми остальными узлами SCN в моем приложении. Пожалуйста, помогите, так как я не могу понять, что именно мне не хватает.
РЕДАКТИРОВАТЬ
В соответствии с рекомендациями я заменил свой init() на
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)
}
}
}
Несмотря на это, выделения в инструментах показывают audioPlayers как постоянные. Хотя при проверке node.audioPlayers он показывает, что в какой-то момент подключен только один узел audioPlayer.
РЕДАКТИРОВАТЬ
Эта проблема возникает даже в простом случае, когда я использую стандартную кодовую базу, прикрепленную в приложении Scenekit, созданном по умолчанию в XCode. Следовательно, эта проблема была поднята Apple как ошибка. https://bugreport.apple.com/web/?problemID=43482539
РЕШЕНИЕ
Я использую AVAudioPlayer вместо SCNAudioPlayer, это не совсем то же самое, но, по крайней мере, память таким образом не вызовет сбоя.
Извините, это простой метод экземпляра, см. developer.apple.com/documentation/scenekit/scnnode/…
В противном случае это просто «let myNode = MyNode ()»; ‘MyNode.soundCasual ()’; ‘MyNode.removeAllAudioPlayers ()’
@StephenFurlani пустой массив [], потому что это должно произойти. AudioNodes после воспроизведения технически удаляются. Но тогда да, если audioNodes добавляются в wrapperNode, тогда как я проверяю себя, это также может быть проблемой в моем ответе здесь.





Я не знаком со 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!
Мне это интересно. Позвольте мне внести все изменения в соответствии с предложением, и я сообщу вам. Поскольку я езжу на работу, это может занять несколько дней. Извинения.
Да, различие между оболочкой и собой кажется проблемой.
Я заинтригован тем, что вы говорите об использовании SCNReferenceNode по сравнению с обычным SCNNode. Было бы первое более эффективным или лучше в каком-то отношении?
@Manganese SCNReferenceNode автоматически загружает файл сцены и является способом санкционированный от Apple для загрузки узлов из файла сцены. Я подозреваю, что Apple делает что-то для оптимизации сборки мусора SCNNode, и, поскольку вы создали эту отдельную сцену, она может не быть ее частью.
Меняю структуру по вашей рекомендации. Добавили его как правку. По-прежнему нет грузовика.
Привет, Стивен, Apple приняла это как ошибку, поскольку я общался с ними. Я буду сообщать об обходном пути, поскольку они уже упоминали, что будут предлагать.
Если вы еще не нашли ответ, вам нужно удалить 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)
}
}
эй, я думаю, я уже пробовал это. Позвольте мне проверить это еще раз, и я вернусь. Извиняюсь, что пропустил ваш пост. Спасибо.
Не могли бы вы показать код для вашего removeAllAudioPlayers ()