There's got to be an easier way of dealing with arrays! - iphone

To optimize a bottleneck, I converted the creation of a large NSArray to a c-style array. (The resulting creation was 1/8 the time of the original NSArray version. Yeah!) But once it's created, speed is no longer an issue, so I'd rather benefit from it being an NSArray again.
However, it seems ridiculously involved to convert a c-style array to an NSArray (unless I'm missing some magic initWithArrayWrapElementsInObjects method.)
As I understand the process now, I first have to create an NSMutableArray, iterate through the c-style array converting each element (floats in my case) to objects, adding each object to the NSMutableArray, then creating the NSArray with the NSMutableArray.
Is that right? There's got to be a better way.
And help would be appreciated.
Thanks!

There's no direct way to take a blob of memory that you own and "convert" it cheaply into an NSArray-- after all, the framework would need to then own that memory, and it doesn't know where you got it from (malloc, stack, etc). If there were a convenience method for initWithArrayWrapElementsInObjects, it would itself need to do internally what you surmise: iterate over your provided memory and add items to itself (it's possibly the framework could do this as quickly as a memcpy, but who knows).
One way you could tackle this (and probably a fun learning exercise) is by actually creating your own subclass of NSArray that manages memory exactly as you want (ie, lets you create and init with whatever semantics you want), but that behaves to the outside world as an NSArray would. You can do this by inheriting from NSArray and implementing the methods count: and objectAtIndex: to operate on whatever memory you're holding on to. Obviously, you'd need to implement the management of your own memory in the init/dealloc, etc methods as well. See this page http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSArray_Class/NSArray.html
under "Subclassing Notes".
The design discussion here hinges on what your data looks like. NSArray, of course, expects its items to be Obj-C references (of type id), and not just arbitrary chunks of data. If your C-style array is holding structures or some other primitive values that aren't object references, then this technique won't really work for you-- NSArray's interface will never be happy with non-reference items.
One final note: you mention taking an NSMutableArray and "creating" an NSArray with it. You should be aware that an NSMutableArray is already an NSArray, since it's a subclass. You can use an instance of NSMutableArray anywhere you'd want an NSArray, without creating some new copy of it.
UPDATE: Missed the note about your array containing floats. Yeah, you're a little bit screwed here. NSArrays want objects. If the capacity doubling was the expensive part (as another poster notes), then try initWithCapacity:. If it's the boxing/unboxing of the floats into object types, there's nothing you can do.
I have created (but don't have handy) a pair of very simple classes (called like MYArray and MYMutableArray) that are intended to wrap just this kind of data with NSArray-like methods on them. But they're not interchangeable with NSArrays. You must use them intentionally.
UPDATE #2. I know it's been ages since this question was live, but I just revisited it and realized there actually is a sort of clever way around this in this specific case. (You want a non-mutable NSArray from a C-style float array). You can create a custom subclass of NSArray that wraps the float values and only converts them to objects when they're accessed via the primitives. This may have performance pitfalls in some corners (?), but it does neatly meet your requirements:
#interface FloatProxyArray : NSArray
{
float * values;
NSUInteger count;
}
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues;
#end
.
#implementation FloatProxyArray
- (id)initWithCArray:(float *)arrayOfFloats count:(int)numberOfValues
{
if ((self = [super init])) {
values = (float *)malloc(numberOfValues * sizeof(float));
if (!values) {
[self release]; return nil;
}
memcpy(values, arrayOfFloats, numberOfValues * sizeof(float));
count = numberOfValues;
}
return self;
}
- (void)dealloc
{
free(values);
[super dealloc]
}
- (NSUInteger)count
{
return count;
}
- (id)objectAtIndex:(NSUInteger)index
{
if (index >= count) {
[NSException raise:NSRangeException format:#""];
return nil;
}
float val = values[index];
return [NSNumber numberWithFloat:val];
}
#end
(N.B. Written in the editor without compiling/testing.)

One optimization that you can do with the NSMutableArray is initWithCapacity which will prevent the doubling of your array which is the expensive operation in the addition.
Outside of that, since NSArrays and NSMutableArrays expect objects, so it's difficult to get around this.

What benefits of it being an NSArray are you looking to get?
It seems like you may be better off with a custom wrapper object around the C array that responds to whatever NSArray messages you are looking to call. Otherwise you are right back at the point of array creation... You could try manually creating a call to initWithObjects, but at the very least every float has to be wrapped in an NSNumber which would bring down your speed again.
If you really need an NSArray because something else you want to use takes NSArray objects, then you are probably better off subclassing NSArray (following the guidelines posted by Ben).

The “best” optimisation (for speed) would almost certainly be to avoid using NSArray altogether, if possible.

Related

Release Objective C object in C-array with ARC

I don't know how to release an Objective-C object that I have stored in an old-fashioned c-array.
(Remark: While writing this after much searching, I think I found a bug in the test-code so this seems to be a solution rather than a question. Well, I've spent a lot of time on it so I'll post it anyway...)
I'd like to convert older code to ARC, because I am spending too much time on debugging memory-management related bugs (sorry---the retain/release rules simply aren't hardwired in my spine, and it takes me literally hours to find a missing retain, because the errors pop up at unrelated moments, probably during or after memory cleanup).
So I have some existing code with c-style arrays (say a two-dimensional array of UILabel*'s), where I can happily calloc() the pointers and access them through some array[col*colstride+row*rowstride], where array is of the type UILabel **; Let's assume the UILabel*s are filled at random order, so I can't use an NSMutableArray for that.
Now in ARC, the compiler wants me to make the type of array to be UILabel *__strong*, it seems (some people write that as __strong UILabel **).
What I don't understand is how I can tell ARC to release the UILabel objects when it is time to do so (say in the dealloc() of my object that uses the c-array). In trying to understand the problem, I have a small set of objects, Memory and MemoryUnit, the former trying to store a large c-array of the latter.
-(Memory*)init {
self = [super init];
if (self) {
MemoryUnit * unit = [[MemoryUnit alloc] init];
array = (__strong id *) calloc(sizeof(MemoryUnit*), 1024);
array[0] = unit;
}
return self;
}
-(void)dealloc {
for (int i=0; i<1024; i++) array[i]=nil;
free(array);
}
In MemoryUnit we have the objects to be stored in the c-array (so this MemoryUnit is in the place of the UILabel mentioned above). For testing I had the code
-(void)dealloc {
NSLog(#"removed %x", (int)self);
}
in its dealloc() for debugging.
As Bryan said, we need an answer in the stack overflow system.
So I do:
Solution
Apparently, setting the array element of type MemoryUnit *__strong to nil causes the object to be released, as if this element had been declared in a #propetty and #synthesize pair of statements. This is actually suggested in C-style array of pointers to Objective-C objects under ARC I think
(I found the documentation in XCode very terse, and the ARC compiler definitions only told me what was not allowed rather than giving a hint on how to do things correctly.)

How does calling retain in different ways on the same object work?

I want to know difference between following two:
NSMutableArray *myArray = [[someObject returnMutableArray] retain];
and
NSMutableArray *myArray = [someObject returnMutableArray];
[myArray retain];
I have some complex data flow project in which I have to return different NSMutableArrays.
I also want to know what is the best way to return NSMutableArrays.
There is no difference apart from how you want your code formatted.
The reason this works is in the documentation for NSObject
As a convenience, retain returns self because it may be used in nested expressions.
Therefore retain returns the object that is was called upon (a mutable array in your case) which means you can nest methods or simply use the return value in the assignment as you have in your example.
For returning values from methods you should make sure it is autorelease'd
So using your snippet
- (NSMutableArray *)myMethod;
{
NSMutableArray *myArray = [someObject returnMutableArray];
// ... do some work
return myArray;
}
Because the method returnMutableArray does not contain the keyword's alloc, new or copy it should be made to return an autorelease'd object. Now as we are returning the object at the end of the method we don't need to take any further retains as it will be ready for returning.
If you are unsure on memory management you should read the Advanced Memory Management Guide or (preferably) start using ARC
There is no difference between 1 and 2.
The best practice on iOS is to return autoreleased objects from methods, and there should be no need to retain them.
If you are confused about how retain and release work, you should probably just enable ARC in your project, which manages retain and release for you automatically.

Most efficient way to find out if an object is already in an NSMutableArray?

I just want to know if an object is in an array or not.
So I can use:
- (BOOL)containsObject:(id)anObj
But it would send -isEqual to every object in the array. Bad when there are thousands of them.
And then there is:
- (NSUInteger)indexOfObjectIdenticalTo:(id)anObject
which seems to only compare the memory addresses. I think this is faster. But a bit nasty to use, of course. One would have to check for NSNotFound.
Is -indexOfObjectIdenticalTo really the best option?
if you really need this often, you can create an instance method by category:
#interface NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object;
#end
#implementation NSArray (MONStuff)
- (BOOL)mon_containsObject:(id)object {
return NSNotFound != [self indexOfObjectIdenticalTo:arg];
}
#end
or these's also CFArrayContainsValue.
a simple function would also suffice.
But a bit nasty to use
Why? It seems to me that
if ([array indexOfObjectIdenticalTo: foo] != NSNotFound)
{
// do what you need
}
is not much more nasty than
if ([array containsObject: foo])
{
// do what you need
}
Which one you choose depends on what equality semantics you use. You almost certainly want to use -containsObject: for arrays containing NSStrings or NSNumbers because -isEqual: gives the correct equality semantics.
Both methods, by the way are O(n) which is where the real performance problem is. If the idea of a linear search is a problem, consider a different data structure e.g. based on NSDictionary.
As per your explaining and comparison indexOfObjectIdenticalTo seems me the first choice to use..
Here is one more SO post ..
indexOfObject vs. indexOfObjectIdenticalTo
If possible (for example if sorting order is irrelevant) you could use an NSDictionary instead, with your object as keys and values of [NSNull null]. Note that the objects get copied when used as keys ! Your objects would need to implement the - (NSUInteger)hash method.
Also see the excellent NSArray or NSSet, NSDictionary or NSMapTable analysis from Matt Gallagher.

How to manage memory load of static, lazily loaded dictionaries and arrays

Generally, I use static arrays and dictionaries for containing lookup tables in my classes. However, with the number of classes creeping quickly into the hundreds, I'm hesitant to continue using this pattern. Even if these static collections are initialized lazily, I've essentially got a bounded memory leak going on as someone uses my app.
Most of these are arrays of strings so I can convert strings into NSInteger constants that can be used with switch statements, etc.
I could just recreate the array/dictionary on every call, but many of these functions are used heavily and/or in tight loops.
So I'm trying to come up with a pattern that is both performant and not persistent.
If I store the information in a plist, does the iphoneOS do anything intelligent about caching those when loaded?
Do you have another method that might be related?
EDIT - ANSWER EXAMPLE
Based on a solution proposed below, here's what I'm going to work with...
First, add a method to NSObject via category.
- (void)autoreleaseOnLowMemory;
Now, whenever I want to create lazy-loading static array or dictionary in a helper function, I can just use the following pattern...
- (id)someHelperFunction:(id)lookupKey {
static NSDictionary *someLookupDictionary = nil;
if (!someLookupDictionary) {
someLookupDictionary = [[NSDictionary dictionaryWithObjects:X, Y, Z, nil] autoreleaseOnLowMemory];
}
return [someLookupDictionary objectForKey:lookupKey];
}
Now, instead of that static dictionary living until the end of the program, if we're running out of memory it will be released, and only re-instantiated when needed again. And yes, in a large project running on an iphone, this can be important!
PS - The implementation of autoreleaseOnLowMemory is trivial. Just create a singleton class with a method that takes an object and retains it in a set. Have that singleton listen for low memory warnings, and if it gets one, release all the objects in that set. May want to add a manual release function as well.
I generally prefer plists for this just because they're easy to maintain and reuse in different sections of code. If the speed of loading them into an NSDictionary from file is a concern (and check the profiler to be sure) you can always put them into an instance variable which you can release when you get a memory warning.
If you are just doing strings, you could use C arrays.
id keys[] = { #"a" , #"b" , #"c" };
id values[] = { #"1" , #"2" , #"3" };
And if you occasionally need a true NSArray or NSDictionary from that:
[NSArray arrayWithObjects:values count:3];
[NSDictionary dictionaryWithObjects:values forKeys:keys count:3];
A plist will involve a disk hit and xml parsing for each collection. As far as I know only NSUserDefaults are cached.

NSMutableArray -init vs. +arrayWithCapacity:

I have two functions which one should i use?
Please explain the difference.
A:
- (NSMutableArray *)FunctionA:(int)count {
NSMutableArray *a = [[NSMutableArray alloc] init];
for (int i = 0; i < count; i++) {
[a addObject:[NSNumber numberWithInt:0] ];
}
return [a autorelease];
}
B:
-(NSMutableArray *)FunctionB:(int)count {
NSMutableArray *b = [NSMutableArray arrayWithCapacity:count];
for (int i=0;i<count; i++){
[b addObject:[NSNumber numberWithInt:0] ];
}
return b; // or [b autorelease] ?
}
The first creates a mutable array without specifying a capacity. This causes the array to have to grow when you add items. Internally, this is probably heavily optimized to occur "chunks at a time" but it's still necessary to grow the array and allocate more space when adding items.
The second gives the array a hint (you're probably going to need "this much" room) to avoid the overhead of growing the array when adding a known number of objects. Of course it will still grow larger if needed (as if you hadn't specified a capacity). You should use this approach if you already know the count ahead of time. It's faster with a large count.
This has a downside if you haven't measured before optimizing, however: If you're creating a mutable array with a very high capacity but not always using that capacity, you incur the penalty of allocating all that space for nothing.
Also, you don't autorelease B (as you commented out) because you didn't create the mutable array with init - you used a convenience method which did it itself, which means you're not responsible for releasing it. As I mentioned in a comment to another answer to your question, you can also create the array with:
[[NSMutableArray alloc] initWithCapacity:capacity];
... then release it when ready. This gives you greater control over memory usage than using the autorelease pool, which is an important consideration on the iPhone platform.
Remember, though: measure first, then optimize if necessary.
Mutable objects still need to allocate space so that will allocate a default amount for say 10 objects. If you add an 11th, the mutable array will have to allocate new memory, copy the items over to the new memory, and free the old memory.
This is normally so fast you won't even notice but it could slow it down. Creating the mutable array with a size creates the array of the specified size initially so hopefully less resizing will occur.
In the first example, you must manage the memory of the array, since you create it using +alloc and -init (which is why you need to send -autorelease to it).
In the second example, you do not have to manage the memory of the array, since it is returned to you autoreleased (because you created it using a convenience method). Also since you specify the desired size of the array up front, it is likely to be more efficient.
If you want to return an autoreleased array, then the second option would probably be more preferable, since +arrayWithCapacity: will return an already autoreleased array. Also since the array returned to you is already autoreleased, you do not have to send -autorelease to it yourself.
If you have any more concerns with memory management, then reading the Apple Memory Management Guidelines is a must.
I'd use B:
The pluses I see with it are
The array will not need to resize as it grows larger
arrayWithCapacity: autoreleases for you so you don't have to, this improves code readability imho
I hope that helps.