Initializing NSMutableArray with and without capacity [duplicate] - objective-c

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
NSMutableArray initWithCapacity nuances
Objective-c NSArray init versus initWithCapacity:0
What is the difference between following line of code? what is the exact advantage and disadvantage? suppose next I will do 3 addObject operation.
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity: 5];
NSMutableArray *array = [[NSMutableArray alloc] init];

Functionally both statements are identical.
In the first case, you are giving the run time a hint that you will soon be adding five objects to the array so it can, if it likes, preallocate some space for them. That means that the first five addObject: invocations may be marginally faster using the first statement.
However, there's no guarantee that the run time does anything but ignore the hint. I never use initWithCapacity: myself. If I ever get to a situation where addObject: is a significant performance bottleneck, I might try it to see if things improve.

Regularly the difference with object oriented languages and arrays of varying sizes is: the overhead you will get and the page faults at the memory level.
To put this in another way imagine you have an object that requests 5 spaces in memory (just like your first example) and the second object doesn't reserve any space. Therefore when an object needs to be added to the first, there will already be space in memory for it to just fall in, on the other hand the non-allocated-object will first have to request for space on memory then add it to the array. This doesn't sound so bad at this level but when your arrays increase in size this becomes more important.
From Apple's documentation:
arrayWithCapacity:
Creates and returns an NSMutableArray object with
enough allocated memory to initially hold a given number of objects.
...
The initial capacity of the new array. Return Value A new NSMutableArray object with
enough allocated memory to hold numItems objects.

Related

The Fastest Way To Alloc 1000000 NSObject?

Normally, we would create 1000000 NSObjects this way.
NSMutableArray* objs = [[NSMutableArray alloc] initWithCapacity:1000000];
for (int i = 0; i < 1000000; i++) {
MyObject* o = [[MyObject alloc] init];
o.str = [NSString stringWithFormat:#"%d", i];
[objs addObject:o];
}
However, this can be very slow. Maybe a lot of the memory allocation should be merged, or there is some other trick to speed it up.
How do I allocate space for several thousand NSObjects more time-efficiently?
Addition:
Using malloc to get a huge number of memory, and re-init it, is also illegal. Since converting from a normal memory into a NSObject will failed with bad access. See below:
There is no short-cut to this problem. If you need to allocate 1 million objects then it will take time and possibly fail due to consuming too much memory.
Given that limitation you need to think about a different solution. For example if each of these objects represents some item then have an ItemManager object that manages as many of these items as necessary. The manager class can then allocate memory in chunks, rather than for individual items, and this will perform much better and be more scalable.
However given you don't explain exactly what these objects represent, I cannot provide a more detailed alternative.

Memory Management ios7 [duplicate]

This question already has answers here:
When to use -retainCount?
(11 answers)
Closed 9 years ago.
I have following code:
- (IBAction)HeyCount:(UIButton *)sender {
NSString* strr = [[NSString alloc] initWithString:#"hi there"];
self.string = #"789";
ohYeah = #"456";
NSLog(#"Retain Count of ohYeah:[%d] with String:[%ld]",[ohYeah retainCount],(long)[ohYeah integerValue]);
NSLog(#"Retain Count of strr:[%d] with String:[%ld]",[strr retainCount],(long)[strr integerValue]);
}
And the out put of the above code is:
Retain Count of ohYeah:[-1] with String:[456]
Retain Count of strr:[-1] with String:[0]
Declaration of ohYeah is in .h file
NSString * ohYeah;
I'm not using ARC. Can anyone of you explain why retain count of both strings is -1 and accessing an object with retain count -1 should not be crash?
I guess the compiler is clever and creates string literals from your given code. Since those reside in their own memory space and are never released they get a retain count of UINT_MAX. UINT_MAX printed with %d will result in -1. Use %u for unsigned integers.
You shouldn't look to closely at retainCount.
There are objects like constant strings that don't take part in the retain/release mechanism. For example, #"456" is such a constant string. You can release or retain it as much as you like, nothing will happen.
There are other objects like #123 that are not even objects in a 64 bit system. They behave like objects, but no memory is ever allocated for them.
In both cases, the retain count won't give any sensible result. Which is why it is very, very rare that you should ever look at the retain count.
And then there are methods like "copy" which sometimes copy an object, sometimes just retain the original object. So if you have an object with a retain count of 100, and you make a copy, that copy might have a retain count of 1 or 101.
Note that retainCount is declared like this in NSObject.h:
- (NSUInteger)retainCount OBJC_ARC_UNAVAILABLE;
You should use %u to display it on 32 bits architecture and %lu on 64 bits.
But you shouldn't use directly retainCount, use it in your code means that you've a problem of architecture, objective-c (ARC or Manual Reference Counting) give a complete set of mechanism to manage memory and objects life cycle properly.

In Objective-C, if addObjectAtIndex is called to built the array, then will initWithCapacity need to be called?

In a book, I see the code:
words = [[NSMutableArray alloc] initWithCapacity:[masterWordList count]];
and let's say [masterWordList count] is 15. And then the code built the array up by using a loop for 10 times:
[words addObject:[masterWordList objectAtIndex:randomNum]];
I wonder why words has to be initWithCapacity... and to 15 slots? Can't it be 10 or 11 (if a nil is needed at the end... and also, won't addObject automatically grow the array size? I tried using init instead of initWithCapacity and the code worked too. So can the code in the book be simplified to just init?
initWithCapacity: simply gives the class initializer a "hint" as to the eventual size of the array. That way, it can allocate enough space in advance if you know you're going to need it. Using initWithCapacity: can theoretically provide for better performance because it may mean that the array doesn't have to reallocate memory (internally) as you add objects to it (I don't know if it actually does this in the current implementation, but it's possible). As you've guessed, it's only a hint and using initWithCapacity: is entirely optional. Just because you've given initWithCapacity: a certain size doesn't mean your array can't grow to hold more elements than that. Also, calling init instead will work just fine.
I wonder why words has to be initWithCapacity... and to 15 slots?
In fact, initWithCapacity: is generally not necessary at all. It may or may not reserve space in a useful way. My understanding is that it's something of a historic appendage.
Can't it be 10 or 11 (if a nil is needed at the end...)
It could be 10. As was mentioned on your other question, nil isn't part of the array. It's just a sentinel value for the creating method call itself -- it's not an object and doesn't become a member of the collection.
also, won't addObject: automatically grow the array size?
Yes it will; you can create a mutable array without specifying any starting size and it will grow as needed.
So can the code in the book be simplified just to init?
Yes.

NSMutableArray vs NSArray which is better

This is a bit of a silly question, but if I want to add an object to an array I can do it with both NSMutableArray and NSArray, which should I use?
NSMutableArray * array1;
[array1 addObject:obj];
NSArray * array2;
array2 = [array2 arrayByAddingObject:obj];
Use NSMutableArray, that is what it is there for. If I was looking at code and I saw NSArray I would expect it's collection to stay constant forever, whereas if I see NSMuteableArray I know that the collection is destined to change.
It might not sound like much right now, but as your project grows and as you spend more time on it you will see the value of this eventually.
NSMutableArray is not threadsafe, while NSArray is. This could be a huge problem if you're multithreading.
NSMutableArray and NSArray both are build on CFArray, performance/complexity should be same. The access time for a value in the array is guaranteed to be at
worst O(lg N) for any implementation, current and future, but will
often be O(1) (constant time). Linear search operations similarly
have a worst case complexity of O(N*lg N), though typically the
bounds will be tighter, and so on. Insertion or deletion operations
will typically be linear in the number of values in the array, but
may be O(N*lg N) clearly in the worst case in some implementations.
When deciding which is best to use:
NSMutableArray is primarily used for when you are building collections and you want to modify them. Think of it as dynamic.
NSArray is used for read only inform and either:
used to populate an NSMutableArray, to perform modifications
used to temporarily store data that is not meant to be edited
What you are actually doing here:
NSArray * array2;
array2 = [array2 arrayByAddingObject:obj];
is you are creating a new NSArray and changing the pointer to the location of the new array you created.
You are leaking memory this way, because it is not cleaning up the old Array before you add a new object.
if you still want to do this you will need to clean up like the following:
NSArray *oldArray;
NSArray *newArray;
newArray = [oldArray arrayByAddingObject:obj];
[oldArray release];
But the best practice is to do the following:
NSMutableArray *mutableArray;
// Initialisation etc
[mutableArray addObject:obj];
An NSArray object manages an immutable array—that is, after you have created the array, you cannot add, remove, or replace objects. You can, however, modify individual elements themselves (if they support modification). The mutability of the collection does not affect the mutability of the objects inside the collection. You should use an immutable array if the array rarely changes, or changes wholesale.
An NSMutableArray object manages a mutable array, which allows the addition and deletion of entries, allocating memory as needed. For example, given an NSMutableArray object that contains just a single dog object, you can add another dog, or a cat, or any other object. You can also, as with an NSArray object, change the dog’s name—and in general, anything that you can do with an NSArray object you can do with an NSMutableArray object. You should use a mutable array if the array changes incrementally or is very large—as large collections take more time to initialize.
Even the Q and the answer are very old, someone has to correct it.
What does "better" mean? Better what? Your Q leaks of information what the problem is and it is highly opinion-based. However, it is not closed.
If you are talking about performance, you can measure it yourself. But remember Donald Knuth: "Premature optimization is the root of all evil".
If I take your Q seriously, "better" can mean runtime performance, memory footprint, or architecture. For the first two topics it is easy to check yourself. So no answer is needed.
On an architectural point of view, things become more complicated.
First of all I have to mention, that having an instance of NSArray does not mean, that it is immutable. This is, because in Cocoa the mutable variants of collections are subclasses of the immutable variants. Therefore an instance of NSMutableArray is an instance of NSArray, but obviously mutable.
One can say that this was no good idea, especially when thinking about Barbara and Jeanette and there is a relation to the circle-ellipse problem, which is not easy to solve. However, it is as it is.
So only the docs can give you the information, whether a returned instance is immutable or not. Or you do a runtime check. For this reason, some people always do a -copy on every mutable collection.
However, mutability is another root of all evil. Therefore: If it is possible, always create an instance of NSArray as final result. Write that in your docs, if you return that instance from a method (esp. getter) or not, so everyone can rely on immutability or not. This prevents unexpected changes "behind the scene". This is important, not 0.000000000003 sec runtime or 130 bytes of memory.
This test gives the best answer:
Method 1:
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
NSMutableArray *mutableItems = [[NSMutableArray alloc] initWithCapacity:1000];
for (int i = 0; i < 10000; i++) {
[mutableItems addObject:[NSDate date]];
}
NSTimeInterval end = [NSDate timeIntervalSinceReferenceDate];
NSLog(#"elapsed time = %g", (end - start) * 1000.0);
Method 2:
...
NSArray *items = [[[NSArray alloc] init] autorelease];
or (int i = 0; i < 10000; i++) {
items = [items arrayByAddingObject:[NSDate date]];
}
...
Output:
Method 1: elapsed time = 0.011135 seconds.
Method 2: elapsed time = 9.712520 seconds.

Using malloc to allocate an array of NSStrings?

Since NSSstring is not defined in length like integer or double, do I run the risk of problems allocating an array of NSStrings for it using malloc?
thanks
ie:
NSString ***nssName;
nssName = (NSString***) malloc(iN * sizeof(NSString*));
the end result with for_loops for the rows is a 2D array, so it is a little easier to work then NSArray(less code).
No problems should arise, allocating an array of NSStrings is like making an array of the pointers to string objects. Pointers are a constant length. I would recommend just using NSArray but it is still fine to use a C array of NSStrings. Note that this may have changed with ARC.
Here is completely acceptable code demonstarting this:
NSString** array = malloc(sizeof(NSString*) * 10); // Array of 10 strings
array[0] = #"Hello World"; // Put on at index 0
NSLog(#"%#", array[0]); // Log string at index 0
Since NSString is an object (and to be more precise: an object cluster) you cannot know its final size in memory, only Objective-C does. So you need to use the Objective-C allocation methods (like [[NSString alloc] init]), you cannot use malloc.
The problem is further that NSString is an object cluster which means you do not get an instance of NSString but a subclass (that you might not even know and should not care about). For example, very often the real class is NSCFString but once you call some of the methods that treat the string like a path you get an instance of NSPathStore2 or whatever). Think of the NSString init methods as being factories (as in Factory Pattern).
After question edit:
What you really want is:
NSString **nssName;
nssName = (NSString**) malloc(iN * sizeof(NSString*));
And then something like:
nssName[0] = #"My string";
nssName[1] = [[NSString alloc] init];
...
This is perfectly fine since you have an array of pointers and the size of pointer is of course known.
But beware of memory management: first, you should make sure the array is filled with NULLs, e.g. with bzero or using calloc:
bzero(nssName, iN * sizeof(NSString*));
Then, before you free the array you need to release each string in the array (and make sure you do not store autoreleased strings; you will need to retain them first).
All in all, you have a lot more pitfalls here. You can go this route but using an NSArray will be easier to handle.
NSStrings can only be dealt with through pointers, so you'd just be making an array of pointers to NSString. Pointers have a defined length, so it's quite possible. However, an NSArray is usually the better option.
You should alloc/init... the NSString*s or use the class's factory methods. If you need an array of them, try NSArray*.
You should not use malloc to allocate data for Objective-C types. Doing this will allocate memory space but not much else. Most importantly the object will not be initialized, and almost as importantly the retain count for the object will not be set. This is just asking for problems. Is there any reason you do not want to use alloc and init?