Blocks and Objects in Objective-C - 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.

Related

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

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

error with NSSring

I'm very new to objective-c and I'm getting a basic error and unsure on how to fix it.
for(ZBarSymbol *sym in syms) {
resultText.text = sym.data; //sym.data = 0012044012482
[self phpPost:(int)sym.data];
break;
}
}
- (void)phpPost: (int)barcode {
NSString *theValue = [NSString stringWithFormat:#"%#", barcode]; //problem line
labelScan.text = theValue;
//labelScan.text = #"Barcode scanned";
}
when i use #"%#" the text of the label is correct (0012044012482), but when i use #"%d" it isn't (random number every time i restart the app). I would like to use #"%#" (or something that works) but for some reason xCode is giving me an error. and I'm unsure on how to fix the error.
The error is:
Format specifies type 'id' but the argument has type 'int'
In the end I plan on having that code (sym.data) written to a MySQL database using the POST method.
You can't just convert it to an int by casting if it's an object (which it must be if the %# format specifier isn't causing a crash).
Assuming from the fact that you're assinging it directly to a label's text that it's an NSString, you should either change the parameter type of phpPost:
- (void)phpPost: (NSString *)barcode {
labelScan.text = barcode;
}
or extract the intValue before passing sym.data:
[self phpPost:[sym.data intValue]];
and then use the proper %d format specifier in phpPost:.
Your barcode isn't an int, it is an NSString. Instead of doing (int)sym.data, pass in [sym.data intValue]. That should correctly convert it to an integer.
The reason you get a random number is because you can't just cast a string object to a primitive data type :)
I don't know what type sym.data is, but it is likely a pointer to an object, and not the value itself. You cast that pointer to int, so when you are using %d you are effectively printing the memory location of the object. That is why it changes each time you run the program (Objective-C let's you do this without any warnings - something to watch out for).
To fix this, either extract the integer value you need from the sym.data object using it's properties; or pass the object as a pointer. For instance, you could try calling your method like this:
[self phpPost:sym.data];
And then change your method to be:
- (void)phpPost: (id)barcode {
NSString *theValue = [NSString stringWithFormat:#"%#", barcode];
labelScan.text = theValue;
}
Ok, I did some thinking while I was at work today, and I figured out that an INT isn't going to work for me. if I make that object to an int, I would loss some data that is vital to what I'm doing. eg. object=001234 int=1234. I need the zeros. So, in the end, I'm keeping it an object (string) and just passing it into the function.
Here is my code after I got it working correctly.
for(ZBarSymbol *sym in syms) {
resultText.text = sym.data;
[self phpPost:sym.data];
break;
}
}
- (void)phpPost: (NSString *)barcode {
labelScan.text = barcode;
//labelScan.text = #"Barcode scanned"; //My custon label
}
Thanks, everyone for your responses. Your answer will not go unused. I'm sure I'll be needing this information here soon.
O, if you see that I did this wrong, or not the correct way, please make a comment and tell me .

Memory error when asking for the count of a NSMutableArray instance

arrayOfBookViews = [[NSMutableArray alloc] init];
BookView *book1 = [[BookView alloc] init];
[arrayOfBookViews addObject:book1];
BookView *book2 = [[BookView alloc] init];
[arrayOfBookViews addObject:book2];
NSLog(#"%#",arrayOfBookViews);
NSLog(#"%#",arrayOfBookViews.count);
Running this code gives me:
(
"",
""
)
which is due to the second last line. The last line then throws me a exc_bad_access memory error. Since the array as well as its objects are properly allocated and initialized, I don't see why asking for the count of the array should give me a memory problem. I'm currently using automatic reference counting in this program with xcode 4.
Please explain why the last line in the code produces a memory error. Thanks.
arrayOfBookViews.count returns an NSUInteger. NSUInteger is not an object, its a primitive. The %# format specifier just calls description on the object passed to it, so you tried to call a method on a primitive which is invalid.
Change the log to NSLog(#"%d",arrayOfBookViews.count); and you'll get your result you wanted.
You trying to print int value. Use %d for this:
NSLog(#"%d",arrayOfBookViews.count);
Please check the return type of NSArray's -count method. You'll find it is an NSUInteger which is a typedef to unsigned int or unsigned long which is a standard C type. You should be using %u or %lu in the format specifier.

Is it safe to use pointers to change values in blocks?

I've started using blocks, and one of the first things I encountered is an inability to set values which are captured by the closure. This is fine, I've been using C/C++ a long time. I'll just use pointers!
MyObject* bestObj = nil;
float bestDist= 10000.f;
MyObject **pBestObj = &bestObj;
float* pBestDist = &bestDist;
[self testObjects:class block:^(MyObject* obj){
CGRect r = [obj boundingBox];
// position is captured from outside this code sample
if( CGRectContainsPoint( r, position ) )
{
float dist = GetDistance( obj, position );
if(dist < bestDist)
{
*pBestDist = dist;
*pBestObj = obj;
}
}
}];
return bestObj;
My question is, is this safe? I assume that as long as my pointer points to something that hasn't gone out of scope and that still exists, that it should work. But I'm also assuming that things that take blocks don't ever, say, run them in parallel. I know my code doesn't, but I don't know about, say, using a block with an NSArray enumerateObjectsUsingBlock call.
The 'right' way to do this would be to mark those original variables as block mutable, __block

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.