how to pass pointer and got the result in function? - iphone

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.

Related

Objective C - CCCallFuncND correct passing of an argument

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"];
}

NSLog pointer syntax

I'm a little bit confused about the syntax of NSLog. For example,
NSString *nameString = #"Name";
NSLog(#"nameString is: %#", nameString);
If my understanding is correct (which it very well may not be), then nameString is defined to be a pointer to a String. I thought then that this would print the memory address that nameString holds, not the value of that address. So, if that is true, then in the NSLog statement, to get the value of the pointer, shouldn't we need to use the asterisk notation to access what nameString points to like this:
NSLog(#"nameString is: %#", *nameString);
?
It has been a little while since programming in C, but since Objective-C is a superset of C I thought they would behave similarly.
An explanation would be greatly appreciated! Thanks!
The command %# is like "shortcut" that calls the method -description on the receiver. For an NSString it simply display the string itself, since is inherited from NSObject you can override it, very usefull if you create for own class. In that case the default behaviur is print the value of the pointer. If you want to print the address of the pointer in the string just replace with :
NSLog(#"nameString is: %p", nameString)
I think that you use an asterisk only to declare a pointer. Then, you only use the name you decided. For example:
NSString *foo = [[NSString alloc] initWithString:#"Hello"];
NSLog(#"%#", foo);
Correct me if I am wrong :)
It's an object and NSLog is a function that uses its format specifiers to determine what to do with the argument. In this case the specifier is %# which tells NSLog to call a method on an object.
Normally this will call the method "description" which returns an NSString but it probably does respondsToMethod first and falls through to some other string methods.

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'."

How to return a array list of non-object type in Objective-C

I have a method which should return a list of non-object types. Specifically a list of CLLocationCoordinate2D. I would like to have it as a list and not as an NSArray I use the outcome to create a MKPolyLine using
+ (MKPolyline *)polylineWithCoordinates:(CLLocationCoordinate2D *)coords count:(NSUInteger)count
With the code below I get an "Array initializer must be an initializer" list.
-(CLLocationCoordinate2D[])pathBetween:(CLLocationCoordinate2D)start and:(CLLocationCoordinate2D)end withNumberofPoints:(int)nrOfPoints{
CLLocationCoordinate2D returnPath[nrOfPoints];
for (int i=0; 1<nrOfPoints; i++) {
float fraction=i/(nrOfPoints);
CLLocationCoordinate2D coord=[self coordinateAtFraction:fraction between:start andEnd:end forAccuracy:.02];
returnPath[i]=coord;
}
return returnPath;
}
If I initialize the list using
CLLocationCoordinate2D returnPath[nrOfPoints]={};
I get "Variable sized object may not be initialized".
If I remove the [] from the method I get "returning 'CLClocationCoordinate2D[nrOfPoints]' from a function with incompatible result type 'CLLocationCoordinate2D'"
Any Ideas?
You are trying to create the array on the stack and then return it. That won't work.
There are several things you can do here:
malloc the array of points.
returnPath = malloc(sizeof(CLLocationCoordinate2D) * nrOfPoints;
This would mean the caller would have to free the returned pointer.
return the array in an NSData
NSMutableData* returnData = [[NSMutableData alloc] initWithLength: sizeof(CLLocationCoordinate2D) * nrOfPoints];
returnPath = [returnData mutableBytes];
// the other stuff
return [returnData autorelease];
This means that you don't have to worry about memory management any more than for any other Objective-C object.
Have the caller supply the array e.g.
-(void) getPath: (CLLocationCoordinate2D*) returnPath // caller allocates a big enough buffer
between: (CLLocationCoordinate2D)start
and: (CLLocationCoordinate2D)end
withNumberofPoints:(int)nrOfPoints
{
// code as question but no allocation or return value
}
CLLocationCoordinate2D returnPath[nrOfPoints]; value for noOfPoints should be available at complile time. if u replace line with CLLocationCoordinate2D *returnPath = (CLLocationCoordinate2D *) malloc(nrOfPoints * sizeof (CLLocationCoordinate2D));
array would be available at run time. But I am not sure sizeof method will return the object size.
As pointed out by Kevin in the comment: you have to do something about the fact that your return argument is a local variable. The reference "returnPath" will point into Nirvana outside your function. Here is a video that explains what happens there, enjoy: http://www.youtube.com/watch?v=6pmWojisM_E
For the array of CLLocationCoordinate2D, look at this post here:
NSMutableArray of ClLocationCoordinate2D
Hope this helps.

How to pass an array to a method and then determine the array's size?

I have this method:
+ (NSData *) createWave: (short[])sampleData {
int i = [sampleData count]; // Warning: Invalid receiver type 'short int *'
}
Inside this method, I'm trying to determine how many elements are in the samples array that was passed in. But I'm getting the warning above (I get the same warning if I change samples to short *).
How can I pass an array like this, and then determine the array's size?
You can't.
Either make sure that the last element in your array is unique and check for that or pass in a size parameter as well i.e.
+ (NSData *) createWave:(short [])samples size:(size_t)count {
int i = count;
}
short[] isn't an object so you can't call methods on it - that's why you're getting a warning (and probably a crash if you run the code!)
You are trying to use a C style array as a parameter and then access it as an Objective-C object. (I am assuming sampleData and samples are supposed to be the same). Use an NSArray of NSNumbers instead because with C style arrays you need to know the length.
+ (NSData *) createWave: (NSArray*)sampleData {
int i = [sampleData count];
}