Сохранение SCNAudioPlayer на узлах SCN в Xcode Instrument

Я создал подкласс 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 источников звука.

Сохранение SCNAudioPlayer на узлах SCN в Xcode Instrument

И это в обязательном порядке происходит со всеми остальными узлами 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, это не совсем то же самое, но, по крайней мере, память таким образом не вызовет сбоя.

Не могли бы вы показать код для вашего removeAllAudioPlayers ()

ekscrypto 09.08.2018 09:17

Извините, это простой метод экземпляра, см. developer.apple.com/documentation/scenekit/scnnode/…

Manganese 09.08.2018 11:33

В противном случае это просто «let myNode = MyNode ()»; ‘MyNode.soundCasual ()’; ‘MyNode.removeAllAudioPlayers ()’

Manganese 09.08.2018 11:38

@Manganese, каков результат .audioPlayers?

Stephen Furlani 09.08.2018 16:34

@StephenFurlani пустой массив [], потому что это должно произойти. AudioNodes после воспроизведения технически удаляются. Но тогда да, если audioNodes добавляются в wrapperNode, тогда как я проверяю себя, это также может быть проблемой в моем ответе здесь.

Manganese 09.08.2018 16:49
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
10
5
494
2

Ответы 2

Я не знаком со 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!

Мне это интересно. Позвольте мне внести все изменения в соответствии с предложением, и я сообщу вам. Поскольку я езжу на работу, это может занять несколько дней. Извинения.

Manganese 09.08.2018 16:50

Да, различие между оболочкой и собой кажется проблемой.

Manganese 09.08.2018 16:51

Я заинтригован тем, что вы говорите об использовании SCNReferenceNode по сравнению с обычным SCNNode. Было бы первое более эффективным или лучше в каком-то отношении?

Manganese 09.08.2018 16:54

@Manganese SCNReferenceNode автоматически загружает файл сцены и является способом санкционированный от Apple для загрузки узлов из файла сцены. Я подозреваю, что Apple делает что-то для оптимизации сборки мусора SCNNode, и, поскольку вы создали эту отдельную сцену, она может не быть ее частью.

Stephen Furlani 09.08.2018 16:58

Меняю структуру по вашей рекомендации. Добавили его как правку. По-прежнему нет грузовика.

Manganese 13.08.2018 11:11

Привет, Стивен, Apple приняла это как ошибку, поскольку я общался с ними. Я буду сообщать об обходном пути, поскольку они уже упоминали, что будут предлагать.

Manganese 21.08.2018 07:16

Если вы еще не нашли ответ, вам нужно удалить 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)
    }
}

эй, я думаю, я уже пробовал это. Позвольте мне проверить это еще раз, и я вернусь. Извиняюсь, что пропустил ваш пост. Спасибо.

Manganese 18.03.2019 18:04

Другие вопросы по теме