Performance issue when converting many floats to NSNumbers - objective-c

In my application, I'm receiving a CSV file that contains 30,000 objects and for each object there are always 24 values (a total of 720,000 values).
Format is something like this:
object1,value1,value2,...,value24
object2,value1,value2,...,value24
...
objectn,value1,value2,...,value24
When I parse this file, I convert each row in an NSArray of NSString.
Next I do the following for each value of the array:
convert from NSString to float using - (float)floatValue
convert the float to an NSNumber
store the NSNumber in an NSMutableArray
This process takes several seconds and from Instruments Time Profiler I'm spending 3.5 s in step 2 & 3 for the 720,000 values.
How can I proceed to avoid the NSNumber translation? Can I use a C style array, something like []? Or CFMutableArrayRef? If it helps, I know there are always 24 values for each object.
Thanks for the help,
Sébastien.

Depending on how you plan to use these values later, there are different ways.
Store entire float array as single NSValue. Pros: construction 24x faster. Cons: you must extract all items to access any of them.
Keep values as strings. Pros: no time wasted. Cons: frequent accesses will waste time.
Design a class that keeps single record: one NSString and 24 float properties. Pros: single record rules everything. Cons: single record rules everything.
upd: If you think of inconvenience manually naming 24 fields value1 .. value24 in case 3, feel free to declare public array in interface section of your class. This will combine nativity of record object with c-style array. You may also add -[valueAtIndex:] and -[setValue:atIndex:] methods to that class and make real array private.

Personally I'd just use a C-style array. If you want to process the data row by row, you could have an object representing each row, something like this:
#interface Row : NSObject {
float values[24];
}
#end
Then you create a Row instance for each row, set the 24 values directly, and add the instance to a NSMutableArray.
Row *row = [[[Row alloc] init] autorelease];
// here's where you read in the data for the row and save the 24 values
row.values[0] = ...
...
row.values[23] = ...
// and here you add the Row instance to an NSMutableArray
[rows addObject:row];
Otherwise, if you know up front you're going to be expecting 30,000 rows then you could preallocate a 30,000 x 24 array of floats.
float *rows = calloc(30000*24, sizeof(float));
for (int i = 0; i < 30000; i++) {
float *values = rows[24*i];
// here's where you read in the data for row i and save the 24 values
values[0] = ...
...
values[23] = ...
}
Just don't forget you'll need to free the memory from that calloc when you're done with it.

Related

Changing NSMutableArray size in objective-c

I was looking around and couldn't find anything, and I'm starting to think it's not possible with objective-c.
I have a NSMutableArray *myMutableArray and the size varies depending on what csv file is loaded. Since I do not set a size of myMutableArray I can't do:
if (c == 5){
myMutableArray[q] = [[NSNumber numberWithFloat:myOtherArray] stringValue];
q = q + 1;
c = 0;
}
Else {
c = c + 1;
}
Since myMutableArray is technically of size nil I guess I can't add objects to it.
In cases, q can be between 1500 and 2500.
My question is, how do I make `myMutableArray' change size on every loop.
If this isn't possible, I guess I will have to make myMutableArray very large - but I need the values in myMutableArray for a graph. If I do myMutableArray = [[NSMutableArray alloc] initWithCapacity:5000]; and don't use the 5000 memory locations, will these locations be nil, or 0? (sorry if the technical words are wrong, by memory locations I mean the memory given to myMutableArray)
Thank you, if there is anything else I can add to this please feel free to let me know.
EDIT: What I'm trying to achieve is adding data to the array, and with that data create a graph
You can't have a sporadically populated array. Creating an array with capacity 5000 is just a hint as to how much data you might be going to store into the array. Consider using an array of dictionaries where the dictionary contains the q value (presumably one coordinate) and the associated value. You can then sort the array based on the q values if you need to (for plotting). Then you can just add the dictionaries to the array as usual (addObject:).
The NSMutableArray class declares the programmatic interface to objects that manage a modifiable array of objects. This class adds insertion and deletion operations to the basic array-handling behavior inherited from NSArray.
If you
arrayWithCapacity:
Creates and returns an NSMutableArray object with enough allocated memory to initially hold a given number of objects.
Mutable arrays expand as needed. When declaring them, we can init them like this:
+ (instancetype)arrayWithCapacity:(NSUInteger)numItems
Here numItems simply establishes the object’s initial capacity.
Later to add more data, i.e. to expand mutable array, use this
addObject:
What it does is, it inserts a given object at the end of the mutable array.
- (void)addObject:(id)anObject
It's important to note that:
The object to add to the end of the array's content. This value must not be nil. It raises an NSInvalidArgumentException if anObject is nil.

Need a more performant way of storing a large amount of floats into an array and reading them back

In my app I have to store path points into an array and then follow those points. To get a smoother run I usually have to dump a path into 5k points. This means I have to store 10k floats- 5k for x and 5k for y coordinates. Right now this is what I'm doing:
1.In the view load I initialize an NSArray with those 10k numbers like this:
pathPoints=[NSArray arrayWithObjects:[NSNumber numberWithFloat:-134.8427], [NSNumber numberWithFloat:148.8433], ....... and so on];
And then I read it like this:
int currentXIndex=..////
[[pathPoints objectAtIndex:currentXIndex] floatValue];
[[pathPoints objectAtIndex:currentXIndex+1] floatValue];
As you can see, each time when I need the next position? I have to unbox it(cast it from NSNumber to float). And I'm sure this takes a great deal of performance. Any suggestions how I can do this another, more performant way?
For a simple container, I'd use a C array and traverse with pointers. Remember that Objective C is a superset of C, so you have everything right there for when the need arise.
edit; sample code:
you don't have to store all numbers 'naked', a struct don't have any overhead:
typedef struct tCoords {
float x, y;
} tCoords;
then just malloc() the size needed:
arraySize = 5000;
tCoords *array = malloc(arraySize * sizeof(tCoords));
and iterate like any simple array:
tCoords *end = array+arraySize;
for (tCoords *p = array; p<end; ++p) {
float x = p->x;
float y = p->y;
}
If you don't like the "old C" look of the code, it's easy to encapsulate all this in a class that 'owns' the array (don't forget to free() it when disposed)
Use a plain array instead of NSArray?
float *pathPoints;
pathPoints = new float[10000];
...
...
delete [] pathPoints;
Or for a constant array
float pathPoints [] = {-134.8427,148.8433, ... and so on};
You can reduce in half the amount of wrapping reasonably cheaply by using [NSValue valueWithPOint:(CGPoint...)] method to box a pair of coordinates as one id object instead of two. This should also reduce the memory required to store the pairs.
If this is not enough, you could "bundle" more elements together in a single wrapper. For example, if you know that your paths are created in groups of, say, 32 points, you can store arrays of 32 CGPoint objects wrapped in NSData (use [NSData dataWithBytes:.. length:..] method). When you need a point at index i, grab a group at index i/32 from NSArray, unwrap from NSData, and then take element at i%32.
If everything else fails, make a class to represent an array of CGPoint structures by hiding calls of malloc and free behind a nice-looking Objective C interface.
you could use a C array of floats...
for info on C arrays:
Resizing an array with C

Check if a variable belongs to an enum value

Is there any way to assign a set of values to an enum and check wether a variable has its value in that enum in objective-c.
Something like getting the index of an object in an array if the object is present in an array. I want to give a common behavior, when certain indexes(may not be in order) tapped in my table view, want to avoid if-ing all the indexes, hope I can use enum style.
Objective-C, like most programming languages, doesn't provide a "type membership" test for primitive types - just for object types (e.g. isKindOfClass:) - so using an enum won't solve your problem.
However given that you are thinking of an enum in the first place it sounds like you have a small fixed set of values you wish to check for. In that case you can just use a static array, e.g. something like:
static NSUInteger indices[] = { 2, 42, 57 };
The number of values in such an array is given by sizeof(indices) / sizeof(NSUInteger and you can write a simple loop or binary search to test for membership.
If you wish to use objects then NSSet is a good choice, if the numbers will vary during execution then NSMutableSet. E.g.
NSSet *indices = [NSSet setWithObjects:#2, #42, #57, nil];
and you test for membership using member::
if ([indices member:#indexToTest] != nil) ...
(Note: unlike NSArray the specification for containsObject: for NSSet does not say it uses isEqual:, hence the use of member: here.)
You can't use an enum for that, because you can't enumerate them or call sth. like contains on them. If I understand your correctly I think the straight forward way to do that would be to just use an NSArray to store the indices you care about. Say you want to recognize the indices 2,6 and 14:
NSArray *indices = [NSArray arrayWithObjects: #2, #6, #14, nil];
(The # is necessary because an NSArray can only store objects. The # turns the integers into NSNumber instances.
Then to check if the currently selected index is in it you use:
int indexToCheck = ...;
BOOL indexIsInArray = [index containsObject:#(indexToCheck)];
If your looking for a more 'fancy' (and faster) way to that, you could use bit operations (again using 2,6 and 14 as example):
int indices = 1 << 2 | 1 << 6 | 1 << 14;
and then to check:
int indexToCheck = ...;
BOOL isValid = (1 << indexToCheck) & indices;
where isValid is true when the indexToCheck in one of your indices.
No, internally enums are based on integers, and the mapping happens at compile time. So you need a specific check for every enum type (if they are consecutive numbers, a ">" and "<" check will do).

NSNumbers being added as values to NSMutableDictionary become nulls

I have a piece of code that constructs a dictionary of objects as keys and operation codes (like add/update/remove) as values.
Recently, either with iOS 6, or with the arrival of "zee Germans", it broke. Values are constructed, and occasionally added, but most of the time I get a dictionary full of (null) values.
for (int i = 0; i < newArray.count; i++)
{
if (![oldArray containsObject:[newArray objectAtIndex:i]])
{
NSNumber *opNumber = [NSNumber numberWithInt:(int)kInsertOperation];
[_operationsForRows setObject:opNumber forKey:[newArray objectAtIndex:i]];
}
else ...
}
I've already decorated the code with intermediate variables and explicit casting of enum value to int, and grew even more confused. Printing out the resulting dictionary gives:
{
"<Order: 0x8aad980>" = (null);
"<Order: 0x8aad7a0>" = (null);
}
Can anyone explain, what am I missing here? The dictionary shouldn't even be able to hold nulls, should it?
This code is under ARC.
NSMutableDictionary was initialized on the main thread, but used exclusively on a single secondary thread.
Sometimes, an object or two would be added correctly. Say, 10%. What I've tried since:
I've moved dictionary initialization to the same thread as usage. Wow, 90-95% of objects are added correctly, but still a null here and there.
I've saved all possible NSNumbers in class fields. With both dictionary and numbers created on main thread, 0% success rate, lower than I started with.
Using current-thread-initialized dictionary and main-thread numbers in class fields, I get to 90-95% again...
Cry, cry... Looks like a rewrite of the whole place.
Try using NSMutableDictionary instead of NSDictionary.
The difference between the two being that you can modify NSMutableDictionary after initialisation whereas NSDictionary is set.

How to build a C array like this dynamically in a loop, return it, and keep a reference?

Right now I have this setup:
An NSMutableArray which stores two NSMutableArray instances.
A for-loop walks over a set of data and writes values into these arrays. It's for a big diagram / chart which is going to be displayed with OpenGL ES.
The NSMutableArray containing two other NSMutableArray objects is returned by a method, and the caller assigns it to a retaining property.
The pitty is this: There can be up to 2.000 values, and I don't like to create all those NSNumber objects.
Now I hope there's a lightweight way to do this with C.
Before I walk the loop I know the number of data points.
Now I want to refactor this so that I get lightweight C-arrays that hold just plain old float values. I know how to create a C-array of float values, but not really dynamically:
CGFloat values[ ] = {
0, 2.5f,
30.2f, 2.5f,
50.95f, 200.55f,
930.2f, 122.1f,
};
Questions:
1) How can I create an array like this dynamically in a loop?
2) How would I put two of those arrays into one array?
3) What about the memory managament? The method returns that multidimensional C-array, and the receiver needs to assign that to an instance variable (property). It needs to be kept around for a while. How could I create an instance variable to hold such an C-array, without knowing it's exact size in advance?
For your first question, you can dynamically create an array using malloc(), and use a pointer variable to store a reference to the first element of it. For example, this will create an array of 8 CGFloats:
CGFloat *a = malloc(8 * sizeof a[0]);
If a is non-NULL, you can then access a[0] through a[7] in the usual way. You can return this CGFloat * value to another function, and when you are done with the array, you must pass this value to free().
For second question, you can create an array of two pointers to the two dynamic arrays:
CGFloat *a[2] = { NULL, NULL };
a[0] = malloc(8 * sizeof a[0][0]);
a[1] = malloc(16 * sizeof a[1][0]);
You can now access a[0][0] through a[0][7] and a[1][0] through a[1][15] (as long as a[0] and a[1] are not NULL).
However, there is a wrinkle here: You cannot directly return arrays in C, so you cannot return a from a function anymore. You could instead use two levels of dynamic arrays, but it probably makes more sense to store the array of pointers within the retaining object in the first place, and pass a reference to this array to the function that fills it in.
This means that your containing object would include the CGFloat *a[2] field, and your function that allocates the dynamic arrays and fills them would include a CFloat *dest[] parameter. That function would start with something like:
dest[0] = malloc(8 * sizeof dest[0][0]);
dest[1] = malloc(16 * sizeof dest[1][0]);
...and then fill in the values as normal.
For the third question, the array that is created by malloc() will live until that pointer is later passed to free(). As mentioned, you can happily return that value and store it elsewhere, as long as you don't free() it until you're done with it.
This will get you a new array:
CGFLoat* myArray = malloc(numberOfFloat * sizeof(float));
You can do things like myArray[6] = 0;.
When you're done with it, you have to call free(myArray), or you will have a memory leak.
With this in mind, your instance variable will just be a CGFloat*.