Objective-C EXC-BAD-ACCESS - resolving without ARC? - objective-c

For reference I'm using Xcode 11.3
I've got an issue with an object that has been released and it's causing EXC BAD ACCESS.
The good news is that I know exactly what the object is.
What I don't know is how to solve for it.
Here's the code where the crash occurs...
- (void)didSendPTPCommand:(NSData*)command inData:(NSData*)data response:(NSData*)response error:(NSError*)error contextInfo:(void*)contextInfo
{
NSLog(#"%# %# %# %#", NSStringFromSelector(_cmd), data, response, error);
PTPOperationRequest* ptpRequest = (__bridge PTPOperationRequest*)contextInfo;
PTPOperationResponse* ptpResponse = NULL;
if ( ptpRequest )
The crash is on:
PTPOperationRequest* ptpRequest = (__bridge PTPOperationRequest*)contextInfo;
This code is being called out of this code:
ptpData = NULL;
PTPOperationRequest* request = [[PTPOperationRequest alloc] init];
request.operationCode = PTPOperationCodeInitiateCapture;
request.numberOfParameters = 0;
commandBuffer = request.commandBuffer;
[camera requestSendPTPCommand:commandBuffer
outData:NULL
sendCommandDelegate:self
didSendCommandSelector:#selector(didSendPTPCommand:inData:response:error:contextInfo:)
contextInfo:(__bridge void * _Nullable)(request)];
where of curse I'm trying to pass "request".
A long time ago I'd have managed this with retain/release - not any more. What do I do now?
David

I think I now have the solution.
__bridge_retained
So the following code is changed thus:
[camera requestSendPTPCommand:commandBuffer
outData:NULL
sendCommandDelegate:self
didSendCommandSelector:#selector(didSendPTPCommand:inData:response:error:contextInfo:)
contextInfo:(__bridge_retained void * _Nullable)(request)];
I have tested and it's working.
David

Related

Creating QR barcodes with ZXingObjC on Mac

I'm trying to use http://github.com/TheLevelUp/ZXingObjC to create QR codes on my Mac app.
It works for every barcode types, but returns nil on QRcode! both 'result' and 'error' is empty. here's my code:
NSError* error = nil;
ZXMultiFormatWriter* writer = [[ZXMultiFormatWriter alloc] init];
ZXBitMatrix* result = [writer encode:#"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"
format:kBarcodeFormatQRCode
width:1750
height:1750 hints:[[ZXEncodeHints alloc] init] error:&error];
if (result) {
CGImageRef image = [[ZXImage imageWithMatrix:result] cgimage];
self.image.image = [[NSImage alloc] initWithCGImage:image size:NSMakeSize(1750, 1750)];
} else {
NSLog(#"error: %#", error);
}
What's wrong on it?
I had the same issue. Here is workaround for this.
Open file ZXingObjC\qrcode\encoder\ZXEncoder.m
Find this row: int minPenalty = NSIntegerMax;. There must be a warning on it: Implicit conversion from 'long' to 'int' changes 9223372036854775807 to -1. That's the reason of the problem. NSIntegerMax returns 9223372036854775807 on my 64-bit Mac and minPenalty gets -1 value (since int type cannot store such a big number).
Replace the NSIntegerMax by INT_MAX. It should return the correct value: 2147483647. That's the number NSIntegerMax returns on 32-bit machines according to the answer to this question.
Run the app and you'll get your QR code!
Try to use another method, not this with HINTS, use just:
[writer encode:#"yourmeganumber" format:kBarcodeFormatQRCode width:xxxx height:xxxx error:&error];
This works for me
Try and let me know

AVAssetReader to AudioQueueBuffer

Currently, I'm doing a little test project to see if I can get samples from an AVAssetReader to play back using an AudioQueue on iOS.
I've read this:
( Play raw uncompressed sound with AudioQueue, no sound )
and this: ( How to correctly read decoded PCM samples on iOS using AVAssetReader -- currently incorrect decoding ),
Which both actually did help. Before reading, I was getting no sound at all. Now, I'm getting sound, but the audio is playing SUPER fast. This is my first foray into audio programming, so any help is greatly appreciated.
I initialize the reader thusly:
NSDictionary * outputSettings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
[NSNumber numberWithFloat:44100.0], AVSampleRateKey,
[NSNumber numberWithInt:2], AVNumberOfChannelsKey,
[NSNumber numberWithInt:16], AVLinearPCMBitDepthKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
[NSNumber numberWithBool:NO], AVLinearPCMIsFloatKey,
[NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
nil];
output = [[AVAssetReaderAudioMixOutput alloc] initWithAudioTracks:uasset.tracks audioSettings:outputSettings];
[reader addOutput:output];
...
And I grab the data thusly:
CMSampleBufferRef ref= [output copyNextSampleBuffer];
// NSLog(#"%#",ref);
if(ref==NULL)
return;
//copy data to file
//read next one
AudioBufferList audioBufferList;
NSMutableData *data = [NSMutableData data];
CMBlockBufferRef blockBuffer;
CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(ref, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
// NSLog(#"%#",blockBuffer);
if(blockBuffer==NULL)
{
[data release];
return;
}
if(&audioBufferList==NULL)
{
[data release];
return;
}
//stash data in same object
for( int y=0; y<audioBufferList.mNumberBuffers; y++ )
{
// NSData* throwData;
AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
[self.delegate streamer:self didGetAudioBuffer:audioBuffer];
/*
Float32 *frame = (Float32*)audioBuffer.mData;
throwData = [NSData dataWithBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
[self.delegate streamer:self didGetAudioBuffer:throwData];
[data appendBytes:audioBuffer.mData length:audioBuffer.mDataByteSize];
*/
}
which eventually brings us to the audio queue, set up in this way:
//Apple's own code for canonical PCM
audioDesc.mSampleRate = 44100.0;
audioDesc.mFormatID = kAudioFormatLinearPCM;
audioDesc.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
audioDesc.mBytesPerPacket = 2 * sizeof (AudioUnitSampleType); // 8
audioDesc.mFramesPerPacket = 1;
audioDesc.mBytesPerFrame = 1 * sizeof (AudioUnitSampleType); // 8
audioDesc.mChannelsPerFrame = 2;
audioDesc.mBitsPerChannel = 8 * sizeof (AudioUnitSampleType); // 32
err = AudioQueueNewOutput(&audioDesc, handler_OSStreamingAudio_queueOutput, self, NULL, NULL, 0, &audioQueue);
if(err){
#pragma warning handle error
//never errs, am using breakpoint to check
return;
}
and we enqueue thusly
while (inNumberBytes)
{
size_t bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
if (bufSpaceRemaining < inNumberBytes)
{
AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
fillBuf->mAudioDataByteSize = bytesFilled;
err = AudioQueueEnqueueBuffer(audioQueue, fillBuf, 0, NULL);
}
bufSpaceRemaining = kAQDefaultBufSize - bytesFilled;
size_t copySize;
if (bufSpaceRemaining < inNumberBytes)
{
copySize = bufSpaceRemaining;
}
else
{
copySize = inNumberBytes;
}
if (bytesFilled > packetBufferSize)
{
return;
}
AudioQueueBufferRef fillBuf = audioQueueBuffer[fillBufferIndex];
memcpy((char*)fillBuf->mAudioData + bytesFilled, (const char*)(inInputData + offset), copySize);
bytesFilled += copySize;
packetsFilled = 0;
inNumberBytes -= copySize;
offset += copySize;
}
}
I tried to be as code inclusive as possible so as to make it easy for everyone to point out where I'm being a moron. That being said, I have a feeling my problem occurs either in the output settings declaration of the track reader or in the actual declaration of the AudioQueue (where I describe to the queue what kind of audio I'm going to be sending it). The fact of the matter is, I don't really know mathematically how to actually generate those numbers (bytes per packet, frames per packet, what have you). An explanation of that would be greatly appreciated, and thanks for the help in advance.
Not sure how much of an answer this is, but there will be too much text and links for a comment and hopefully it will help (maybe guide you to your answer).
First off I know with my current project adjusting the sample rate will effect the speed of the sound, so you can try to play with those settings. But 44k is what I see in most default implementation including the apple example SpeakHere. However I would spend some time comparing your code to that example because there are quite a few differences. like checking before enqueueing.
First check out this posting https://stackoverflow.com/a/4299665/530933
It talks about how you need to know the audio format, specifically how many bytes in a frame, and casting appropriately
also good luck. I have had quite a few questions posted here, apple forums, and the ios forum (not the official one). With very little responses/help. To get where I am today (audio recording & streaming in ulaw) I ended up having to open an Apple Dev Support Ticket. Which prior to tackling the audio I never knew existed (dev support). One good thing is that if you have a valid dev account you get 2 incidents for free! CoreAudio is not fun. Documentation is sparse, and besides SpeakHere there are not many examples. One thing I did find is that the framework headers do have some good info and this book. Unfortunately I have only started the book otherwise I may be able to help you further.
You can also check some of my own postings which I have tried to answer to the best of my abilities.
This is my main audio question which I have spent alot of time on to compile all pertinent links and code.
using AQRecorder (audioqueue recorder example) in an objective c class
trying to use AVAssetWriter for ulaw audio (2)
For some reason, even though every example I've seen of the audio queue using LPCM had
ASBD.mBitsPerChannel = 8* sizeof (AudioUnitSampleType);
For me it turns out I needed
ASBD.mBitsPerChannel = 2*bytesPerSample;
for a description of:
ASBD.mFormatID = kAudioFormatLinearPCM;
ASBD.mFormatFlags = kAudioFormatFlagsAudioUnitCanonical;
ASBD.mBytesPerPacket = bytesPerSample;
ASBD.mBytesPerFrame = bytesPerSample;
ASBD.mFramesPerPacket = 1;
ASBD.mBitsPerChannel = 2*bytesPerSample;
ASBD.mChannelsPerFrame = 2;
ASBD.mSampleRate = 48000;
I have no idea why this works, which bothers me a great deal... but hopefully I can figure it all out eventually.
If anyone can explain to me why this works, I'd be very thankful.

Recursive Blocks in Objective-C leaking in ARC

So I'm using recursive blocks. I understand that for a block to be recursive it needs to be preceded by the __block keyword, and it must be copied so it can be put on the heap. However, when I do this, it is showing up as a leak in Instruments. Does anybody know why or how I can get around it?
Please note in the code below I've got references to a lot of other blocks, but none of them are recursive.
__block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString *function){
LinkedList *list = [[LinkedList alloc] init];
NSDictionary *dict;
FormulaType type;
while (cformula.count > 0) {
dict = cformula.pop;
type = [[dict objectForKey:#"type"] intValue];
if (type == formulaOperandOpenParen || type == formulaListOperand || type == formulaOpenParen) [list add:ProcessElementStack(cformula, [dict objectForKey:#"name"])];
else if (type == formulaField || type == formulaConstant) [list add:NumberForDict(dict)];
else if (type == formulaOperand) [list add:[dict objectForKey:#"name"]];
else if (type == formulaCloseParen) {
if (function){
if ([function isEqualToString:#"AVG("]) return Average(list);
if ([function isEqualToString:#"MIN("]) return Minimum(list);
if ([function isEqualToString:#"MAX("]) return Maximum(list);
if ([function isEqualToString:#"SQRT("]) return SquareRoot(list);
if ([function isEqualToString:#"ABS("]) return EvaluateStack(list).absoluteValue;
return EvaluateStack(list);
} else break;
}
}
return EvaluateStack(list);
} copy];
NSDecimalNumber *number = ProcessElementStack([formula copy], nil);
UPDATE
So in my own research I've discovered that the problem apparently does have to do with the references to the other blocks this block uses. If I do something simple like this, it doesn't leak:
__block void (^LeakingBlock)(int) = [^(int i){
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
However, if I add a another block in this, it does leak:
void (^Log)(int) = ^(int i){
NSLog(#"log sub %i", i);
};
__block void (^LeakingBlock)(int) = [^(int i){
Log(i);
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
I've tried using the __block keyword for Log() and also tried copying it, but it still leaks. Any ideas?
UPDATE 2
I found a way to prevent the leak, but it's a bit onerous. If I convert the passed in block to a weak id, and then cast the weak id back into a the block type, I can prevent the leak.
void (^Log)(int) = ^(int i){
NSLog(#"log sub %i", i);
};
__weak id WeakLogID = Log;
__block void (^LeakingBlock)(int) = [^(int i){
void (^WeakLog)(int) = WeakLogID;
WeakLog(i);
if (i < 100) LeakingBlock(++i);
} copy];
LeakingBlock(1);
Surely there's a better way?
Ok, I found the answer on my own...but thanks to those who tried to help.
If you're referencing/using other blocks in a recursive block, you must pass them in as weak variables. Of course, __weak only applies to block pointer types, so you must typedef them first. Here's the final solution:
typedef void (^IntBlock)(int);
IntBlock __weak Log = ^(int i){
NSLog(#"log sub %i", i);
};
__block void (^LeakingBlock)(int) = ^(int i){
Log(i);
if (i < 100) LeakingBlock(++i);
};
LeakingBlock(1);
The above code doesn't leak.
Aaron,
As your code appears to be single threaded, why are you copying the block? If you don't copy the block, you don't have a leak.
Andrew
Without further context information, I can say this:
You are leaking that block because you are copying it and not releasing it elsewhere. You need to copy it to move it to the heap, that's ok. But the way you've chosen is not entirely ok.
A correct way to do it is to store it as some object instance variable, copy it, and then release it inside dealloc. At least, that's a way to do it without leaking.

Blocks and Objects in Objective-C

I've started learning how to use blocks/functions/lambda in Objective-C. But I can't get it to work with Objects. Probably I'm missing some pointer, but it's not working however I do.
This is my code for the moment:
MyEventArgs (^skapaEventArg)(Operation);
skapaEventArg = ^(Operation a) { return *[[MyEventArgs alloc] initWithOperation:a]; };
MyEventArgs *a = skapaEventArg(Add);
But I get the error that this pic shows:
If I do
MyEventArgs a = skapaEventArg(Add);
to put it on the stack, Xcode gives me the usual "Interface cannot be statically allocated"-error
How do I get this simple code to work, using blocks?
It should be:
MyEventArgs *(^skapaEventArg)(Operation);
skapaEventArg = ^(Operation a) { return [[MyEventArgs alloc] initWithOperation:a]; };
MyEventArgs *a = skapaEventArg(Add);
Note the * in the first line, and the lack of it in the second line.
return *[[MyEventArgs alloc] initWithOperation:a];
I think you get "incompatible type" error because you return dereferenced pointer.

Warning Pass-by-Value?

I am fairly new to Objective-C and whilst running the Clang static analyser this section of code gave me the following error
warning: Pass-by-value argument in message expression is undefined
[artistCollection removeObject:removeArtist];
Can anyone cast any light on this warning for me?
case 6:
NSLog(#"(*) - First Name:");
scanf("%s", userFirName);
objFirName = [[NSString alloc] initWithUTF8String:userFirName];
for(eachArtist in artistCollection) {
if([[eachArtist firName] isEqualToString: objFirName]) {
removeArtist = eachArtist;
}
}
[artistCollection removeObject:removeArtist];
[objFirName release], objFirName = nil;
break;
gary
If you never get a match on that if inside your loop (because userFirName isn't in your collection), removeArtist will never get assigned a value. Assign it a value before starting the loop (nil, probably), and you should be fine.