 |
 |
NSMutableArray vs a plain C Array for storing floats
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jul 2004
Status:
Offline
|
|
Hello,
I am in the process of modifying a subclass of NSTableView which allows for dynamically-resizing rows. This subclass adds two NSMutableArray instance methods to store all of the varying row heights and all of the row origins (because these can no longer be quickly calculated using simple multiplications of a set height, obviously). These arrays store floats as NSNumber objects. The author says on his website that he has not properly optimised this subclass, and I was wondering, would there be a noticeable differrence in performance for large tables if I replaced these NSMutableArrays with plain C arrays of floats?
To this purpose, I have created a structure containing a pointer to a float array and an integer for a count of the array's elements, and a couple of functions that I can use in place of addObject: and removeLastObject, as follows:
Code:
typedef struct
{
float *array; // Pointer for holding an array of floats
int count; // Integer for holding the current number of floats stored in the pointer
} floatArray;
BOOL AddFloatToArray ( floatArray *farray, float newFloat )
{
// Allocate new array with the capacity for one more float than the old array
float *newArray = (float *)malloc ( (farray->count + 1 ) * sizeof (float) );
// If there was an error, return NO
if (newArray == NULL)
return NO;
if ( farray->count > 0 ) // Only do this if there is anything in the old array
{
// Copy the old array into the new array
int i;
for (i = 0; i < (farray->count); i++)
newArray[i] = farray->array[i];
// Deallocate the old array
free(farray->array);
}
// And now add the new float to the end of the new array, in the new space we have allocated
// and increase the count of floats accordingly
newArray[farray->count] = newFloat;
farray->count += 1;
// Finally, set it to point to the new array
farray->array = newArray;
return YES;
}
BOOL RemoveLastFloatFromArray ( floatArray *farray )
{
if (farray->count > 0) // Can't remove anything if there is nothing to remove
{
// Decrease the count
farray->count -= 1;
if (farray->count > 0) // Only create a new array if there is anything left
{
// Allocate new array with the capacity for one less float than the old array
float *newArray = (float *)malloc (farray->count * sizeof (float));
// If there was an error, return NO
if (newArray == NULL)
return NO;
// Copy the old array into the new array, except for the last element
int i;
for (i = 0; i < farray->count; i++)
newArray[i] = farray->array[i];
// Deallocate the old array
free(farray->array);
// Finally, set it to point to the new array
farray->array = newArray;
}
else
{
// The new array is empty
free(farray->array);
}
return YES;
}
else
return NO; // Nothing was done...
}
So, my question is just, will these functions and the use of plain C arrays in place of NSMutableArray improve performance? I haven't noticed any particular performance problems as it is, but I haven't been able to test with any enormous tables as of yet, and I want to allow for large tables with large chunks of text in each cell in the program I am working on.
Many thanks for any advice,
KB
|
|
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
This is probably a case of premature optimization. The difference probably won't be noticeable until you're into thousands of array elements. But since you've already written the code, you may as well try it and find out.
I noticed a few issues with your Add function. You can optimize it quite a bit by using realloc instead of malloc'ing a new pointer and copying the elements one by one. If you did want to use malloc, you'd still get better results by using memcpy to just copy the contents of the old pointer into the new one. But use realloc and don't worry about it.
But to answer generally, using straight C for collections will always be substantially faster than using dynamic messaging in objective-C because, duh, you're not using the overhead of dynamic messaging.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Dec 2000
Location: sj ca
Status:
Offline
|
|
I've found that the time it takes me to design/implement/debug things like this in C (as opposed to ObjC) significantly outweighs any performance gains.
|
|
|
| |
|
|
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jul 2004
Status:
Offline
|
|
Thank you both very much for your useful replies.
smeger - many thanks for the pointer on realloc, I went straight to my Kernighan and Ritchie and rewrote the functions as follows:
Code:
BOOL AddFloatToArray ( floatArray *farray, float newFloat )
{
if ( farray->count > 0 )
{
// The array is already allocated, just enlarge it by one
farray->array = realloc ( farray->array, ((farray->count + 1) * sizeof (float)) );
// If there was an error, return NO
if (farray->array == NULL)
return NO;
}
else
{
// Allocate new array with the capacity for one float
farray->array = (float *)malloc ( sizeof (float) );
// If there was an error, return NO
if (farray->array == NULL)
return NO;
}
farray->array[farray->count] = newFloat;
farray->count += 1;
return YES;
}
BOOL RemoveLastFloatFromArray ( floatArray *farray )
{
if (farray->count > 0) // Can't remove anything if there is nothing to remove
{
// Decrease the count
farray->count -= 1;
// If count is now zero, this is the equivalent of calling free():
farray->array = realloc (farray->array, (farray->count * sizeof (float)) );
// If there was an error, return NO
if (farray->array == NULL)
return NO;
return YES;
}
else
return NO; // Nothing was done...
}
I thought this might well be a case of premature optimisation, but it's also a useful exercise as it's given me a purpose in going through somebody else's subclass and helps me broaden my understanding of the classes and Obj-C and Cocoa in general. I doubt anyone will create a table of thousands of entries in my program, though, so I guess it will never make any real difference.
gyn - Thanks, that sounds good advice for the future. Fortunately in this case it wasn't much more work than a simple find and replace.
Many thanks again,
KB
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Nov 2000
Location: Tasmania, Australia
Status:
Offline
|
|
Variable row heights for NSTableView is something we should have had from Apple ages ago. It's been frustrating many developers for a looong time.
I think you'll find that Apple will have this in NSTableView eventually. Strong change it will be there in the first half of next year, I'm guessing 
|
|
|
| |
|
|
|
 |
|
 |
|
Fresh-Faced Recruit
Join Date: Jul 2004
Status:
Offline
|
|
We can but hope.  I've only been using Cocoa a couple of months, and I was quite surprised that tables didn't already have this feature. In the meantime, this subclass is working very well. It's the one by Evan Jones:
http://www.eng.uwaterloo.ca/~ejones/...tableview.html
(But with a few very minor amendments of my own.) It turns out that this optimisation wasn't premature after all. When the subclass was storing row heights and origins in NSMutableArrays of NSNumbers, there were lots of weird drawing issues while live resizing the window or columns (presumably because this caused a lot of calls to the values in the array, as it had to work out how to resize the height of each row dynamically). I didn't think much of this, seeing as the problem seemed to disappear if grid lines were switched on (I have no idea why that would be).
However, on replacing the NSMutableArrays with straight C arrays and the functions above, the drawing issues seem to have disappeared (touch wood). I tested with two identical tables with the same data, one using NSMutableArrays and one using C arrays, and the one using NSMutableArrays had all sorts of drawing glitches compared to the "optimised" version.
So, er, I guess I answered my own question. It makes quite a large difference in certain cases (like this one). But thanks again to smeger for helping me optimise my add and remove functions, and to everyone else for their input.
Thanks,
KB
|
|
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|