4

iOS アプリでの同期で再生を処理するために、The Amazing Audio Engine を使用しています。

フレームワークでは、オーディオ スレッドで呼び出されるコール バック (playbackTimingReceiver) として C 関数を使用する必要があります。次に、ハンドラー (pageTurnHandler) を渡す C 関数 (AEAudioControllerSendAsynchronousMessageToMainThread) を使用して、メイン スレッドに再度メッセージを送信する必要があります。

私はCでの作業にあまり経験がありませんが、私が理解しているように、逆参照する必要があるメッセージにポインターを渡しています。

次の行で正常に達成できます。

PlaybackManager* receiver = *((PlaybackManager**)userInfo);

ただし、プロジェクトターゲットのコンパイル済みソースで -fno-objc-arc フラグを使用して、そのファイルのプロジェクトで ARC をオフにした場合のみです。

私の質問に対して、ARCをオンにしてこれを達成することは可能ですか? もしそうなら、正しい構文は何ですか?

関連するコード セグメント:

#pragma mark - Audio Timing Callback
-(AEAudioControllerTimingCallback)timingReceiverCallback
{
    return playbackTimingReceiver;
}

static void playbackTimingReceiver(PlaybackManager* receiver,
                                   AEAudioController *audioController,
                                   const AudioTimeStamp *time,
                                   UInt32 const frames,
                                   AEAudioTimingContext context)
{
    receiver->_hostTime = getUptimeInMilliseconds(time->mHostTime);
    AEAudioControllerSendAsynchronousMessageToMainThread(audioController,
                                                         pageTurnHandler,
                                                         &audioController,
                                                         sizeof(id));
}

static void pageTurnHandler(AEAudioController *audioController, void *userInfo, int userInfoLength)
{
    PlaybackManager* receiver = *((PlaybackManager**)userInfo);
    NSLog(@"Receiver:%@", receiver);
}
4

3 に答える 3

2
PlaybackManager * receiver = (__bridge_transfer id)*(void **)userInfo;

トリックを行う必要があります。userInfoこれには、元のオブジェクト ポインターのアドレスが含まれているため、最初にポインター ツー ポインターにキャストされます。それを逆参照して元のポインターを取得__bridge_transferし、タイプで使用するか、idまたはPlaybackManager動作するようにして、逆参照された値が実際には処理する必要があるオブジェクトであることを ARC に伝えます。

于 2013-07-19T00:01:40.110 に答える
1

コードを実行しないと、次の 2 つのエラーが発生するようです。

1) の内容audioControllerを渡すつもりだったように見えるときに、の内容を渡しています。receiverしたがって、最後の 2 つの引数は&にするAEAudioControllerSendAsynchronousMessageToMainThread必要があります。&receiversizeof(PlaykbackManager *)

2) オブジェクト参照を元に戻すには、ブリッジ キャストが必要です。

何かのようなもの:

static void playbackTimingReceiver(PlaybackManager* receiver,
                                   AEAudioController *audioController,
                                   const AudioTimeStamp *time,
                                   UInt32 const frames,
                                   AEAudioTimingContext context)
{
    receiver->_hostTime = getUptimeInMilliseconds(time->mHostTime);
    AEAudioControllerSendAsynchronousMessageToMainThread(audioController,
                                                         pageTurnHandler,
                                                         &receiver,
                                                         sizeof(PlaybackManager*));
}

static void pageTurnHandler(AEAudioController *audioController, void *userInfo, int userInfoLength)
{
    PlaybackManager* receiver = (__bridge Playback *)*((PlaybackManager**)userInfo);
    NSLog(@"Receiver:%@", receiver);
}

注: オブジェクト参照を ARC 制御ワールドから C ワールドに渡す場合、途中で所有権を転送することがよくあります。そのため、ARC は参照されたオブジェクトを解放しません。また、戻る途中で所有権を転送します。したがって、ARC は所有権管理を再開します。ただし、 の性質上AEAudioControllerSendAsynchronousMessageToMainThread、 whereuserInfoはアドレスで渡され、内部でコピーされます。つまり、サイズの引数であるため、所有権を譲渡するのは巧妙です。したがって、上記のコードはそうではありません。receiverこれは、別の所有者を持つことによって、オブジェクト参照が生き続けることを確認する必要があることを意味します。

于 2013-07-19T00:46:29.290 に答える
0

必要なストレージのタイプを ARC に伝えるだけです。

PlaybackManager *audioBufferPlayer = *(__weak PlaybackManager **)userInfo;

プロパティにアクセスしたりメソッドを呼び出したりする前に、必ず必要な nil チェックを行ってください。

于 2016-12-13T07:58:49.303 に答える