Pointer to difference with ARC in function C in iOS

I use The Amazing Audio Engine to control sync playback in an iOS app.

The structure requires that you use the C functions as a callback (playbackTimingReceiver) that is called in the audio stream. Then you need to send the main thread again using the C function (AEAudioControllerSendAsynchronousMessageToMainThread) with which you pass the handler (pageTurnHandler).

I'm not too experienced working with C, but as far as I understand, I pass the pointer in the message that needs to be dereferenced.

What I can achieve successfully with the line:

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

But only if I disable ARC in the project for this file using the -fno-objc-arc flag in the compiled sources in the target project.

To my question, is it possible to achieve this with ARC enabled? If so, what is the correct syntax?

Corresponding code segment:

 #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
source share
3 answers
 PlaybackManager * receiver = (__bridge_transfer id)*(void **)userInfo; 

gotta do the trick. First, it puts userInfo in a pointer to a pointer, because it contains the address of the source pointer of the object. The difference is that to get the source pointer and use __bridge_transfer with type - id or PlaybackManager will work - tell ARC that the dereferenced value is actually an object that it needs to take care of.

+2
source

Without running the code, two errors occur:

1) You pass the contents of the audioController when it looks like you wanted to pass the contents of the receiver - so the last two arguments of AEAudioControllerSendAsynchronousMessageToMainThread should be &receiver and sizeof(PlaykbackManager *)

2) To get a link back to an object, you need a bridge roll

Sort of:

 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); } 

Note: when you transfer references to objects from the world controlled by ARC to world C, you often transfer ownership of the path, so ARC does not release the object that it refers to and transfers ownership back to the return path - therefore, ARC resumes property management. However, due to the nature of AEAudioControllerSendAsynchronousMessageToMainThread , where userInfo is passed to the address and copied internally - hence the size argument, it tricks the transfer of ownership. Therefore, the above code does not. This means that you must ensure that any receiver object of the link remains alive, having a different owner.

+1
source

You can simply specify the ARC type of storage you would like:

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

Just remember to do null checks before accessing any properties or calling any methods.

0
source

Source: https://habr.com/ru/post/1492191/


All Articles