How to return an array - objective-c

I need to return an array but don't know how to do this, here is how it looks
CGPoint position[] = {
CGPointMake(500, 200),
CGPointMake(500, 200)
};
return position;
But I get an error of incompatible result. Any way around this error? Need to return multiple positions.

You can do something like this
NSArray *position = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(500, 200)],
[NSValue valueWithCGPoint:CGPointMake(600, 300)],
nil];
for getting the values from array
for(int i=0; i<[position count]; i++) {
NSValue *value = [position objectAtIndex:i];
CGPoint point = [value CGPointValue];
NSLog(#"%#",NSStringFromCGPoint(point);
}

With UIKit Apple added support for CGPoint to NSValue, so you can do:
NSArray *points = [NSArray arrayWithObjects:
[NSValue valueWithCGPoint:CGPointMake(5.5, 6.6)],
[NSValue valueWithCGPoint:CGPointMake(7.7, 8.8)],
nil];
List as many [NSValue] instances as you have CGPoint, and end the list in nil. All objects in this structure are auto-released.
On the flip side, when you're pulling the values out of the array:
NSValue *val = [points objectAtIndex:0];
CGPoint p = [val CGPointValue];

If you don't want to use NSArray and since CGPoint is a struct you can return it the C way
CGPoint *position = malloc(sizeof(CGPoint)*2);
position[0] = CGPointMake(500,200);
position[1] = CGPointMake(500,200);
return position;
although the drawback is that the calling function doesn't know the number of elements in the array, you may need to tell this in some other manner.
also you need to free the returning array once you are done with it using free();
although using NSArray/NSMutableArray is more convenient.

Related

How To Compare Integer to Objective-C enum

- (void)updateCheckBoxes {
NSArray *availableFuncUnits = _scanner.availableFunctionalUnitTypes;
for(int i = 0; i < [availableFuncUnits count]; i++) {
}
}
If I put a breakpoint inside the for loop, the elements of the NSArray * 'availableFuncUnits' are (__NSCFNumber *)(int)0 and (__NSCFNumber *)(long)3.
The array is supposed to contain elements of the following :
enum
{
ICScannerFunctionalUnitTypeFlatbed = 0,
ICScannerFunctionalUnitTypePositiveTransparency = 1,
ICScannerFunctionalUnitTypeNegativeTransparency = 2,
ICScannerFunctionalUnitTypeDocumentFeeder = 3
};
typedef NSUInteger ICScannerFunctionalUnitType;
Shouldn't I be able to do the following?
if([availableFuncUnits objectAtIndex:i] == ICScannerFunctionalUnitType.ICScannerFunctionalUnitTypeDocumentFeeder) {}
But it always gives me an error saying 'Expected identifier or '('.
How can I perform this comparison correctly? Thanks a lot for the help!
There are two problems that I see:
1) The array availableFuncUnits contains NSNumber objects. You cant directly compare them with primitive types (NSUInteger).
So your if should be like this:
ICScannerFunctionalUnitType type = [availableFuncUnits[i] integerValue]
if(type == ICScannerFunctionalUnitTypeDocumentFeeder){}
In your snippet you were comparing the pointer, not the object.
2) The error you were seeing is because the proper way to use enums is:
i = ICScannerFunctionalUnitTypeDocumentFeeder
You can't store integers in an NSArray because array's can only contain objects. To get integers into an array they must be wrapped with NSNumber:
NSInteger a = 100;
NSInteger b = 200;
NSInteger c = 300;
// Creating NSNumber objects the long way
NSArray *arrayOne = [NSArray alloc] initWithObjects:[NSNumber numberWithInteger:a],
[NSNumber numberWithInteger:b],
[NSNumber numberWithInteger:c], nil];
// Creating NSNumber objects the short way
NSArray *arrayTwo = [[NSArray alloc] initWithObjects:#100, #200, #300, nil];
This is relevant you your question because when you extract your NSNumber objects from your array, if you want to then compare them to actual integers, you must convert them back to integers (unwrap them).
NSLog(#"%d", [arrayOne firstObject] == 100); // COMPILER WARNING!!!
NSLog(#"%d", [[arrayOne firstObject] integerValue] == 100); // True
NSLog(#"%d", [[arrayTwo lastObject] integerValue] == 200); // False
This stage appears to be missing in your example.
Finally to compare your integer values with those from an enum, there's no need to reference the enum name, just use the individual values that make up the enum:
[[arrayTwo lastObject] integerValue] == ICScannerFunctionalUnitTypeFlatbed

What's the best way for custom sort to NSMutableArray that contains objects

I saw many examples for Custom sort for NSMutableArray , here one of them
How to sort an NSMutableArray with custom objects in it?, but I have an object with a and b, and I want to sort them according to a*b.
I saw this code for example
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"birthDate"
ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [drinkDetails sortedArrayUsingDescriptors:sortDescriptors];
But I do not have birthDate here I need to sort according to a*b (both double)?
More details,
I have a NSMutableArray that contains CGRect objects, and I want to sort them according to width*height
I agree with the previous solutions. You can put CGRects in an array by wrapping them into an NSValue:
CGRect rect = CGRectMake(0, 10, 20, 30);
NSValue *valueToPutInArray = [NSValue valueWithCGRect:rect];
and sort them with a block like this:
NSArray *sortedArray = [rectArray sortedArrayUsingComparator:^NSComparisonResult(NSValue *rectAValue, NSValue *rectBValue) {
CGRect rectA = [rectAValue CGRectValue];
CGRect rectB = [rectBValue CGRectValue];
CGFloat areaA = rectA.size.width * rectA.size.height;
CGFloat areaB = rectB.size.width * rectB.size.height;
if (areaA < areaB)
{
return NSOrderedAscending;
}
else if (areaB > areaA)
{
return NSOrderedDescending;
}
else
{
return NSOrderedSame;
}
}];
Another solution would be to wrap the CGRect into a custom object and add a function to it like
- (CGFloat)area
{
return self.rect.size.width * self.rect.size.height;
}
(self.rect is the wrapped rect)
If you populate your array with those custom objects you can sort it with your original method by creating a sort descriptor like
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"area" ascending:YES];
This will simply compare the results of the area function and sort the array accruing to that.
A NSSortDescriptor is not suitable for anything more complex than comparing a simple key, or possibly a set of keys.
You'll want to sort using a custom comparator (a block). Something like
sortedArray = [myArray sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
MyObject *first = (MyObject*)a;
MyObject *second = (MyObject*)b;
if (first.a * first.b < second.a * second.b) {
return NSOrderedAscending;
}
else if (first.a * first.b > second.a * second.b) {
return NSOrderedDescending;
}
return NSOrderedSame;
}]
Note I'm just winging it as far as your (a*b) description goes, not really sure what you want there.
The easiest way to implement custom sorting is to use -[NSMutableArray sortUsingComparator: or -[NSArray sortedArrayUsingComparator:].
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
// Compare stuff, return a NSComparisonResult.
return [obj1 compare:obj2];
}];
I like to explicitly pass the object types in the block, BTW. For example, for strings:
sortedArray = [drinkDetails sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
// Compare stuff, return a NSComparisonResult.
return [obj1 localizedCaseInsensitiveCompare:obj2];
}];

Indexing arrays

Overview
I have painting APP. It registers mouse events and sends it to NSMutableArray. Later values from array are being transfered to GLfloat and drawn like vertex array. So all brush stroke is redrawn at every mouse event.
What I want to do?
I want to implement undo-redo functions and something like brush stroke variety (softness and etc), so I need somehow to do that every vertex (mouse event location) could have few additional settings. I want to ask if it is possible at all.
Explanation
If user draws 10 points with 100% softness (in one mouse drag) and then changes softness to 0% and draws, first 10 point's brush texture has to be set to img1 and second brush stroke brush's texture has to be set to img2.
If there would be possibility for indexing arrays (for example something like this NSMutableArray *array[i++] = [[NSMutableArray alloc] init]) I think it would be possible to do something similar to what I want pretty easy. But is it possible? Or maby you could suggest any other solution?
P.S. NSMutableArray *array[i++] = [[NSMutableArray alloc] init] doesn't shows me any error, but does't works too.
Attempt using NSMutableDictionary
At mousedown and mousedragged:
locll = [self convertPoint: [event locationInWindow] fromView:nil];
NSValue *locationValuell = [NSValue valueWithPoint:locll];
[vertices addObject:locationValuell];
at mouseUp
NSString *index = [NSString stringWithFormat:#"%d", aIndex++];
[aDict setObject:vertices forKey:index];
NSArray *allKeys = [aDict allKeys];
NSLog(#"dict count: %ld", [allKeys count]);
NSString *index1 = [NSString stringWithFormat:#"%d", aIndex];
NSMutableArray *a = [aDict objectForKey:index1];
NSLog(#"a count:%li", [a count]);
at initWithCoder
int aIndex = 0;
dict count returns how many objects are stored in dictionary. And it works. But later when I try to get array back from dictionary, I check how much objects array has and it returns 0.
If i understand your question right , here's what you can do :
Every mouse drag will be 1 path i.e an NSMutableArray of points
with same softness level.
Add this to a NSMutableDictionary with Key as the
softness-level and Value with this path array.
Iterate through the dictionary to get the corresponding Key-Value
pair and draw the strokes.
For UNDO just delete the last object of the dictionary and store in
a temporary dictionary.
For REDO fetch it back from the temporary dictionary and add to the main dictionary.
Thanx for posting the code. I tried this and it works absolutely fine :
- (void)viewDidLoad
{
[super viewDidLoad];
int aIndex = 0;
NSMutableDictionary *aDict =[[NSMutableDictionary alloc]init];
NSMutableArray *vertices = [[NSMutableArray alloc]init];
[vertices addObject:#"one"];
[vertices addObject:#"two"];
[vertices addObject:#"three"];
NSString *index = [NSString stringWithFormat:#"%d", aIndex++];
[aDict setObject:vertices forKey:index];
NSArray *allKeys = [aDict allKeys];
NSLog(#"dict count: %d", [allKeys count]); // Prints 1
NSMutableArray *a =[aDict objectForKey:index];
NSLog(#"a item count is :%d", [a count]); // prints 3
}
NOTE: Be careful with the index you are passing.
You can work with your array as other objects so, you can use [YourArray insertObject:YourArray atIndex:i++]] then use [YourArray objectAtIndex:i] to get your array back
Good Luck
You can create a vector or VAOs and add a VAO to it for each brush stroke. Wrap the VAOs in a class that also holds additional information such as brush type. That should let you identify each stroke's type and correctly render them.

Can't withdraw CGPoint Values from A mutableArray of NSValue

I made an NSMUtableArray of CGpoints and I stored them by subclassing as NSValue, but I cant get the values out. here I what I did.
CGPoint graphPoint;
NSMutableArray *pointValues = [[NSMutableArray alloc] init];
for( int x =0;x<5; x++)
{
NSDictionary* xValue = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:x] forKey:#"X"];
graphPoint.x =x;
graphPoint.y = [CalculatorBrain runProgram: self.graphingPoint usingVariableValues:xValue];
[pointValues addObject:[NSValue valueWithCGPoint:graphPoint]];
}
I tried using this to get the values but I just get null back
for( int x=0; x<5; x++) {
NSValue *val = [pointValues objectAtIndex:x];
CGPoint point = [val CGpointValue];
NSLog(#"Points = %#", point);
}
You can't print a CGPoint using the %# format specifier, as it is not an object. Instead, use NSStringFromCGPoint():
NSLog(#"%#", NSStringFromCGPoint(myPoint));

Getting CGRect from array

For my application I am trying to store CGRect objects into an NSMutableArray. It is loading well and printing in the log statement, but trying to take the CGRects from the array shows an error. Here is a code snippet:
CGRect lineRact = CGRectMake([[attributeDict objectForKey:#"x"] floatValue],
[[attributeDict objectForKey:#"y"] floatValue],
[[attributeDict objectForKey:#"width"] floatValue],
[[attributeDict objectForKey:#"height"] floatValue]);
[lineRactangle addObject:NSStringFromCGRect(lineRact)];
How can I get the rects back from the array?
A CGRect is a struct, not an object, and thus cannot be stored in NSArrays or NSDictionaries. You can turn it into a string and turn that string back into a CGRect, but the best way is to encapsulate it via an NSValue:
NSValue *myValue = [NSValue valueWithCGRect:myCGRect];
You can then store this NSValue object in arrays and dictionaries. To turn it back into a CGRect, you'd do:
CGRect myOtherCGRect = [myValue CGRectValue];
[lineRactangle addObject:[NSValue valueWithCGRect:lineRect]];
Use NSValue to wrap CGRect thus store them in NSArrays.
For example:
CGRect r = CGRectMake(1,2,3,4);
NSValue *v = [NSValue valueWithCGRect:rect];
NSArray *a = [NSArray arrayWithObject:v];
CGRect r2 = [[a lastObject] CGRectValue];
See documentation for the other supported structures.
Actually, I don't think any of the answers thus far really address the question ajay asked. The short answer is: You need to supply CGRectMake with the intValue, rather than the floatValue of the dictionary item. If you need to do this for several CGRects, here's a suggested method:
- (CGRect) NSArrayToCGRect: (NSDictionary *) attributeDict
{
int x = [[attributeDict objectForKey:#"x"] intValue];
int y = [[attributeDict objectForKey:#"y"] intValue];
int w = [[attributeDict objectForKey:#"width"] intValue];
int h = [[attributeDict objectForKey:#"height"] intValue];
return CGRectFromString([NSString stringWithFormat: #"{{%d,%d},{%d,%d}}", x, y, w, h]);
}
There may be a more elegant way to accomplish this, but the above code does work.
If your object can be set with ".frame" you could use:
// {{CGFloat x,CGFloat y}, {CGFloat width,CGFloat height}}
NSString *objectCoords = #"{{116,371},{85,42}}";
myObject.frame = CGRectFromString(objectcoords);
or for multiple objects:
NSArray *objectCoords = [NSArray arrayWithObjects:
#"{{116,371},{85,42}}",
#"{{173,43},{85,42}}",
#"{{145,200},{85,42}}",
nil];
myObject1.frame = CGRectFromString([objectCoords objectAtIndex:0]);
myObject2.frame = CGRectFromString([objectCoords objectAtIndex:1]);
myObject3.frame = CGRectFromString([objectCoords objectAtIndex:2]);
CGRect is a struct you cannot put it in an NSArray. You can only add objects to it.
or something more 'extreme'... creating an array that holds arrays of CGRect(s)
movPosTable = [[NSArray alloc] initWithObjects:
[[NSArray alloc] initWithObjects: [NSValue valueWithCGRect:[GridAB frame]], [NSValue valueWithCGRect:[GridBA frame]], [NSValue valueWithCGRect:[GridBB frame]], nil],
[[NSArray alloc] initWithObjects: [NSValue valueWithCGRect:[GridAA frame]], [NSValue valueWithCGRect:[GridAC frame]], [NSValue valueWithCGRect:[GridBA frame]], [NSValue valueWithCGRect:[GridBB frame]], [NSValue valueWithCGRect:[GridBC frame]], nil],
[[NSArray alloc] initWithObjects: [NSValue valueWithCGRect:[GridAB frame]], [NSValue valueWithCGRect:[GridBB frame]], [NSValue valueWithCGRect:[GridBC frame]], nil], nil];
where 'GridAA', 'GridAB' etc. correspond to UIViews