Objective C - CCCallFuncND correct passing of an argument - iphone

I've been trying to call the function below.It seems that whenever in the function playNote I'm trying to access the object that I'm passing as the argument (myNum) it always crashes. I'm very new and I probably don't understand how to pass parameters through CCCallFuncND. All comments are appreciated.
This is the call that passes the argument myNum:
id action2 = [CCCallFuncND actionWithTarget:self selector:#selector(playNote:data:) data:(NSNumber *)myNum];
This is the whole block:
- (void)muteAndPlayNote:(NSInteger)noteValue :(CCLayer*)currentLayer
{
myNum = [NSNumber numberWithInteger:noteValue];
NSLog(#"Test the number: %d", [myNum integerValue]);
id action1 = [CCCallFunc actionWithTarget:self selector:#selector(muteAudioInput)];
id action2 = [CCCallFuncND actionWithTarget:self selector:#selector(playNote:data:) data:(NSNumber *)myNum];
id action3 = [CCDelayTime actionWithDuration:3];
id action4 = [CCCallFunc actionWithTarget:self selector:#selector(unmuteAudioInput)];
[currentLayer runAction: [CCSequence actions:action1, action2, action3, action4, nil]];
}
NSLog never displays anything it crashes at this line.
- (void) playNote:(id)sender data:(NSNumber *)MIDInoteValue
{
NSLog(#"Test number 2: %d", [MIDInoteValue integerValue]);
int myInt = [MIDInoteValue floatValue];
[PdBase sendFloat: 55 toReceiver:#"midinote"];
[PdBase sendBangToReceiver:#"trigger"];
}

Note that CCCallFunc* actions are inherently unsafe if you're using ARC.
Regardless of that it's generally better to use CCCallBlock* actions (which are safe to use under ARC) because then you often don't even need to pass in data as parameters, you can just use the variables of the local scope inside the block:
myNum = [NSNumber numberWithInteger:noteValue];
[CCCallBlock actionWithBlock:^{
NSInteger myInt = [myNum integerValue];
// do something with myInt, or just use noteValue directly
}];
PS: check your code for data type consistency. You create NSNumber myNum as an NSInteger value, later you get it via the floatValue method which implicitly converts the number to float and then back to int (use integerValue instead). You assign it to an int value which is the same as int only on 32 bit systems, on 64 bit systems like iPhone 5S NSInteger is actually a 64 bit type (use NSInteger instead of int).
You can get nasty value conversion issues (as well as issues when building for 64 bit devices) if you aren't consistent in using the exact same data type. Plus you're possibly even getting warnings about this already - take those warnings seriously.

Your method signature is:
-(void)playNote:(id)sender data:(NSNumber*)MIDInoteValue
but it should be:
-(void)playNote:(id)sender data:(void*)data
This is defined in the CCActionInstant.h as:
typedef void (*CC_CALLBACK_ND)(id, SEL, id, void *);
Also I'm pretty sure you get some information from the crash, like the call stack end the console output, would be helpful to paste it here in case I'm wrong ;)

For those encountering problems with this function, here are the working versions:
id action2 = [CCCallFuncND actionWithTarget:self selector:#selector(playNote:data:) data:(void *)noteValue];
and then the definition:
- (void) playNote:(id)sender data:(void *)midiNoteCode
{
int myNum = midiNoteCode; //void * to int conversion may cause problems on 64bit platform, wrap it into NSInteger
[PdBase sendFloat: (float)myNum toReceiver:#"midinote"];
[PdBase sendBangToReceiver:#"trigger"];
}

Related

is there any way to get the return value from a method by using #selector except using double pointer?

I don't want to use double pointer. I am using a function in simpler form as below.
-(NSString *) getName
{
return name;
}
So what is the correct way to take the returned NSString *?
By using #selector(getName) i am not able to get the returned value name.
Thank you in advance
You should use NSInvocation object instance for calling a selector and resolving returned result.
performSelector: does give you the return value directly.
NSString * s = #"NEXT WE HAVE NUMBER FOUR, 'CRUNCHY FROG'.";
NSString * l = [s performSelector:#selector(lowercaseString)];
NSLog(#"%#", l); // prints "next we have number four, 'crunchy frog'."

Can't do mathematical operations with int from NSUserDefaults

i have integer data, stored in NSUserDefaults, there is my code:
- (IBAction)addButton:(id)sender {
NSInteger oldValue = [[NSUserDefaults standardUserDefaults] integerForKey:#"myValue"];
NSString *string1=[addTextField text];
int add = [string1 floatValue];
int new = globalCalories;
int old=oldValue;
if(recomended.text==[NSString stringWithFormat:#"%i", oldValue]){
**self.day = (int)roundf(old-add);
dayLeft.text=[NSString stringWithFormat:#"%d", oldValue-add];
}**
else
{
self.day=(int)roundf(new-add);
dayLeft.text=[NSString stringWithFormat:#"%d", day];
}
}
I copied all of button action code, just in case, but i did mark with bold strings of code, that appear to not work. So, it suppose to do mathematical operations with stored data (oldValue), but when i launch programs, it dosnt, in fact, it does, but instead of valid value program "think" that oldValue is 0 (instead of valid value).
So, when it contain, for example, number 2000, and I launch program and enter in text field 500, it suppose to be 1500 (2000-500), but it shows -500.
You can convert recommended.text to integer by using this:
int recommendedValue = [recommended.text intValue];
then compare the numbers.
The problem is that == compared the address es of the NSString and not their values (see many SO questions). To compare strings use the isEqualToString: method.
However in this case it would be even better to compare the numbers ie convert recomended.text to the number and use a intValue method on dayLeft.

how to pass pointer and got the result in function?

please see code as follow :
- (BOOL)postAction :( NSString*) url params:(NSDictionary*) params bodySize:(NSNumber**)bodySize
{
...
int size = 1999;
NSNumber* value =[[NSNumber alloc] initWithInt:size];
bodySize = &value;
...}
use the function as follows:
NSNumber* size ;
[self postAction:#"http://webserver/ss.php" params:params bodySize:&size];
// can not got the size value at all…
int i = [size intValue];
//will throw nil exception !
my question is that how to correct this code above ?
many thanks for your help !
Regards
If you are using pass-by-reference in iOS or Mac OS X, you are probably doing it wrong.
Seriously-- pass by reference is an exceedingly rare pattern to use. It is pretty much entirely reserved to (NSError**) across the APIs.
Not to say that there isn't a reason to use pass-by-reference, but this isn't it.
Specifically, if you need to return an NSNumber, then return it!
- (NSNumber *) foo;
If that method returns nil, that is just as good as returning a BOOL NO. And it sets you up to follow the very common pattern of using NSError:
- (NSNumber *) foo: (NSError **) error;
Ideally, you should always check the pointer before dereferencing it:
If ( bodySize )
*bodySize = value;
I think you want this:
//bodySize = &value;
*bodySize = value;
I agree with the above two answers. To be more clear, NSNumber is an object (Unlike NSInteger or NSUInteger). So you should directly point your pointer to that object.

NSComparisonResult and NSComparator - what are they?

What is NSComparisonResult and NSComparator?
I've seen one of the type definitions, something like that:
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
Is it any different from a function pointer?
Also, I can't even guess what the ^ symbol means.
^ signifies a block type, similar in concept to a function pointer.
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
// ^ ^ ^
// return type of block type name arguments
This means that the type NSComparator is a block that takes in two objects of type id called obj1 and obj2, and returns an NSComparisonResult.
Specifically NSComparator is defined in the Foundation Data Types reference.
And to learn more about C blocks, check out this ADC article Blocks Programming Topics.
Example:
NSComparator compareStuff = ^(id obj1, id obj2) {
return NSOrderedSame;
};
NSComparisonResult compResult = compareStuff(someObject, someOtherObject);
Jacob's answer is good, however to answer the part about "how is this different than a function pointer?":
1) A block is not a function pointer. Blocks are Apple's take on how to make functions first class citizens in C/C++/Objective-C. It's new to iOS 4.0.
2) Why introduce this strange concept? Turns out first class functions are useful in quite a few scenarios, for example managing chunks of work that can be executed in parallel, as in Grand Central Dispatch. Beyond GCD, the theory is important enough that there are entire software systems based around it. Lisp was one of the first.
3) You will see this concept in many other languages, but by different names. For example Microsoft .Net has lambdas and delegates (no relation to Objective-C delegates), while the most generic names are probably anonymous functions or first class functions.
NSComparisonResult comparisionresult;
NSString * alphabet1;
NSString * alphabet2;
// Case 1
alphabet1 = #"a";
alphabet2 = #"A";
comparisionresult = [alphabet1 caseInsensitiveCompare:alphabet2];
if (comparisionresult == NSOrderedSame)
NSLog(#"a and a are same. And the NSComparisionResult Value is %ld \n\n", comparisionresult);
//Result: a and a are same. And the NSComparisionResult Value is 0
// Case 2
alphabet1 = #"a";
alphabet2 = #"B";
comparisionresult = [alphabet1 caseInsensitiveCompare:alphabet2];
if (comparisionresult == NSOrderedAscending)
NSLog(#"a is greater than b. And the NSComparisionResult Value is %ld \n\n", comparisionresult);
//Result: a is greater than b. And the NSComparisionResult Value is -1
// Case 3
alphabet1 = #"B";
alphabet2 = #"a";
comparisionresult = [alphabet1 caseInsensitiveCompare:alphabet2];
if (comparisionresult == NSOrderedDescending)
NSLog(#"b is less than a. And the NSComparisionResult Value is %ld", comparisionresult);
//Result: b is less than a. And the NSComparisionResult Value is 1

NSNumber, Setting and Retrieving

I'm messing around with NSNumber for an iPhone app, and seeing what I can do with it. For most of my variables, I simple store them as "int" or "float" or whatnot. However, when I have to pass an object (Such as in a Dictionary) then I need them as an Object. I use NSNUmber. This is how I initialize the object.
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
Where "varMoney" is an int I have declared earlier in the program. However, I have absolutely no idea how to get that number back...
for example:
varMoney2 = [NSNumber retrieve the variable...];
How do I get the value back from the object and set it to a regular "int" again?
Thanks!
(Out of curiosity, is there a way to store "int" directly in an Objective-C dictionary without putting it in an NSNumber first?)
You want -intValue, or one of its friends (-floatValue, -doubleValue, etc.). From the docs:
intValue Returns the receiver’s value
as an int.
- (int)intValue
Return Value The receiver’s value as
an int, converting it as necessary.
The code would be:
int varMoney2 = [testNum intValue];
NSNumber *testNum = [NSNumber numberWithInt:varMoney];
/* Then later... */
int newVarMoney = [testNum intValue];