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

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

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

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.

address of ivar as an argument

I am trying to call function but I get error:
warning: passing argument 1 of 'drawPlot' from incompatible pointer type
//call
drawPlot(&listData);
//header
void drawPlot(NSMutableArray*);
listData is of course NSMutableArray
Remove the &. Your variable is already a pointer. I assume you've declared it like so: NSMutableArray *listData;.
So using & is passing a "pointer to a pointer" to a function that is expecting simply a pointer to an NSMutableArray.
Now, there are a number of places in the SDK that expect NSError **. And this is when you would use &, e.g:
NSError *error = nil;
...
[SomeClass doSomethingReturningError:&error];
if (error != nil) {
//something bad happened
}
So, the difference here is that passing, in your case, listData passes the object by value. The variable's value itself cannot be modified (but the contents of the array can be). The other case (&error) is passing by reference, which means that the the value of the variable, i.e. the pointer itself, can be modified. That is why you can compare the result, in that case, to nil to see if something went wrong.
A simpler example is to compare the difference between the following:
void changeIntByValue(int i)
{
i++;
}
void changeIntByReference(int &i)
{
i++;
}
int x=2;
changeIntByValue(x);
NSLog(#"%d", x); // prints 2
changeIntByReference(&x);
NSLog(#"%d", x); // prints 3
Passing by value does not allow arguments to be modified, while passing by reference does.
Definition of listData should look something like:
NSMutableAarray listData; //OR
NSMutableAarray listData[];
If the former, then change the drawPlot call to
drawPlot(&listData[0]) // OR
drawPlot(listData)
If the latter, then change the drawPlot call to
drawPlot(&listData [ the index of the listData array member you want to plot]); // does it work now?

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.

What kind of data is in an "enum" type constant? How to add it to an NSArray?

What kind of information is stored behind such an enum type thing? Example:
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
I am not sure if I can safely add such an enum constant to an array. Any idea?
Enums in Objective-C are exactly the same as those in C. Each item in your enum is automatically given an integer value, by default starting with zero.
For the example you provided: UIViewAnimationCurveEaseInOut would be 0; UIViewAnimationCurveEaseIn would be 1, and so on.
You can specify the value for the enum if required:
typedef enum {
UIViewAnimationCurveEaseInOut,
UIViewAnimationCurveEaseIn = 0,
UIViewAnimationCurveEaseOut,
UIViewAnimationCurveLinear
} UIViewAnimationCurve;
This result of this would be: UIViewAnimationCurveEaseInOut is 0; UIViewAnimationCurveEaseIn is 0; UIViewAnimationCurveEaseOut is 1; and so on. However, for basic purposes you shouldn't need to do anything like that; it just gives you some useful info to toy with.
It should be noted based on the above, that an enum can't assume to be a unique value; different enum identifiers can be equal in value to each other.
Adding an enum item to a NSArray is as simple as adding an integer. The only difference would be that you use the enum identifer instead.
[myArray addObject:[NSNumber numberWithInt:UIViewAnimationCurveEaseInOut]];
You can check this out for yourself by simply outputting each enum to the console and checking the value it provides you with. This gives you the opportunity to investigate the details of how it operates. But for the most part you won't really need to know on a day to day basis.
Enums are typically int values. You can store them in an array by wrapping them in an NSNumber:
[myMutableArray addObject:[NSNumber numberWithInt:myAnimationCurve]];
... then get them back out like this:
UIViewAnimationCurve myAnimationCurve = [[myMutableArray lastObject] intValue];
Enums in Objective-C are the same as enums in vanilla C. It's just an int. If you're using an NSArray, then it expects a pointer and you'll get a warning if you try to add an int to it:
NSMutableArray *myArray = [[NSMutableArray alloc] init];
[myArray addObject:UIViewAnimationCurveEaseInOut];
// Last line results in:
// warning: passing argument 1 of 'addObject:' makes
// pointer from integer without a cast
If you're storing a large collection of 32-bit integers, consider using the appropriate CF collection type rather than the NS collection type. These allow you to pass in custom retain methods, which gets rid of the need to box every integer added to the collection.
For example, let's say you want a straight array of 32-bit ints. Use:
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
The last parameter tells the array to not retain/release the "addresses" you pass in to it. So when you do something like this:
CFArrayAppendValue(arrayRef, 1);
What the array thinks is that you're passing in a pointer to an object living at the memory address 0x1. But since you told it to not call retain/release on that pointer, it gets treated as a standard int by the collection.
FWIW, for educational value, standard NSMutableArrays have equivalent CF types. Through toll-free bridging you can use the CF collection as a standard Foundation collection:
CFMutableArrayRef arrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, kCFTypeArrayCallbacks);
NSMutableArray *array = (NSMutableArray *)arrayRef;
[array addObject:#"hi there!"];
NSLog(#"%#", [array objectAtIndex:0]); // prints "hi there!"
You can apply the same tricks to dictionaries (with CFDictionary/CFMutableDictionary), sets (CFSet/CFMutableSet), etc.