Should reversing an NSMutableArray be avoided when possible? - objective-c

Assume I have NSNumbers 1 - 450. I can choose to add them to an NSMutableArray either starting with 1 and ending with 450, or starting with 450 and ending with 1. My code would be a little simpler if I could start with 1 and end with 450, but when the time finally comes for me to enumerate over the array, I will ultimately need to reverse it. In other words, I need the first object in the enumeration to be 450, and the last one to be 1.
Since my code would be simpler if I do it this way (add starting with 1, then reverse it prior to enumeration), it's my preferred method. However, the Apple documentation for - (NSEnumerator *)reverseObjectEnumerator says:
It is more efficient to use the fast enumeration protocol (see
NSFastEnumeration). Fast enumeration is available on Mac OS X v10.5
and later and iOS 2.0 and later.
So should I avoid the array reversal and simply write slightly more complicated code so that the NSMutableArray gets created in the desired order in the first place?

You can use fast enumeration with an NSEnumerator instance, the documentation about fast enumeration even uses the reverseObjectEnumerator: method as an example:
NSEnumerator *enumerator = [array reverseObjectEnumerator];
for (NSString *element in enumerator) {
//...
}
Besides, your question sounds a lot like premature optimization...

No, you do not need to write the more complicated code to put it in the right order. The reverseObjectEnumerator will work fine, it is only marginally slower. If performance is a big concern, either of the snippets below will work well (the faster of the two being the while loop)
// Assuming 'array' is your NSMutableArray
int i = [array count];
while(i--) {
Object *current = [array objectAtIndex:i];
// Mess around with current
}
That will start you at 450 and end at 0. You can also do this with a for loop, though you need to make sure that you either start with index 449, or you do something like
for(int i = [array count]; i > 0 ; i--) {
Object *curreyt = [array objectAtIndex:i-1];
// Mess around with current
}

Related

Creating an array based on multiple conditions

This is more of a logic question. I wanted to see different approaches.
I am trying to create a filter array based on multiple criteria. Let's say I have 4 boolean criteria,
I will set these with a simple toggle button.
NSObject* A; BOOL booleanA TRUE;
NSObject* B;BOOL booleanB FALSE;
NSObject* C;BOOL booleanC TRUE;
NSObject* D;BOOL booleanD FALSE;
What I want to achieve is to end up with an array with objects with TRUE boolean values like :
NSArray: {A, C}
I was going to use the most straightforward approach:
if(booleanA)[array addObject:A];
if(booleanB)[array addObject:B];
if(booleanC)[array addObject:C];
if(booleanD)[array addObject:D];
Looks fine to me, but maybe you can come up with something different and simpler. I literally cant think of any other way.
You look for an algorithmic solution. Right now, you manually transform 4 (unrelated, albeit similar named) BOOLs into 1 array. You can only write an algorithm when there's a 1:1 match, instead of a N:1 transformation. So I suggest you try to put booleanA to booleanD in a container instead of fiddling around with seemingly unrelated variables.
If you put the booleans into an array with fixed positions, using consts or macros for the indexes (booleans[B_INDEX]), you can write an algorithm to transform the truthiness at index i into letter A+i, so to speak.
If you use a small collection class instead, you can even get rid of handling arrays and matching indexes.
I would prefer a collection class so that the other class using this stuff doesn't get too bloated. The four lines you show look similar, but since the BOOLs have nothing in common but their name, you won't be able to write an algorithm yet. Encapsulating an algorithm like #user3571918 proposed will hide the matching from your calling class. Also, it hides the fact that 4 lines of manual transformation may have turned into a 30+ lines value object or service class :)
Will using a more complex, algorithmic solution pay off? I think this is the case if you plan on adding more switches later so you don't have to change the calling class just because its data representation was extended.
Example code
Here's an example algo I'd put into a utility class to hide the fact that the number of elements is fixed from other classes.
NSArray *booleans = #[#0, #1, #0, #1]; // array representation
NSArray *transformations = #[#"A", #"B", #"C", #"D"]; // matching utility
NSMutableArray *result = [NSMutableArray array];
[booleans savedArray enumerateObjectsUsingBlock:^(NSNumber *boolean, NSUInteger idx, BOOL *stop) {
BOOL isToggled = [boolean booleanValue];
id transformation = transformations[idx];
if (isToggled)
{
[result addObject:transformation];
}
}];
// result will be: #[#"B", #"D"];
How you assemble booleans depends on the code you already have. Maybe handing the toggle switches over as a variadic argument list to a utility method works, maybe it will be simpler.
The issue is that a Boolean operator is not an object. You might be better off utilizing #0 and #1 for your purposes, and no matter what you'd have to objectify your Boolean value to place in NSArray. The workaround for that is to utilize a C array, however, since you asked for a more convenient way to derive your answer utilizing Objective-C, I'll stick with that.
Basically, I think your question boils down to 'how to enumerate NSArray' and there are some options. Here's a good high level resource regarding NSArray. There are other ways to do it, and especially flexible with enumerateWithBlock as described here previously.
With fast enumeration you can have code that may look similar to the following:
NSArray* array = #[#0, #1, #0, #1];
for (NSNumber* number in array) {
if ([number isEqualToNumber:#0]) {
// action here
return;
}
// else action here
}

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.

Quick NSMutableArray Question

I was wondering, would using a NSMutableArray be the best way for making an array that i will be adding objects to? Or, just a regular NSArray? secondly, I'm trying to make something sort of like an ArrayList in java (so there is no limit to the size), and I would like to know how to do that. What I've thought of is to make a bigger array and copy older array into it. My code:
- (void) addAccount:(BankAccount *)b
{
accountCount = [NSNumber numberWithDouble:[accountCount doubleValue] + 1];
NSMutableArray *oldList = accounts;
accounts = [[NSMutableArray alloc] (some code to make bigger and copy over)];
}
P.S. I taught myself this language yesterday, so I may not understand you response if it's too advanced
NSMutableArrays are what you want. Also, NSMutableArrays are already like ArrayLists or STL vectors, or anything else with "no limit to the size". You can say [myArray addObject:someObject]; until you run out of memory, and it will just keep resizing itself as needed.
The difference between an NSMutableArray and an NSArray lies in the meaning of the word "mutable". i.e.: A mutable array can be modified after it's created whereas a "normal" NSArray is immutable and can't be modified after it's created.
As such, using an NSMutableArray and adding objects to it via the addObject: method would seem an ideal solution.
If you want to be adding objects all at once use NSArray. If you're going to be adding some objects now, then more later, use NSMutableArray.
Your code snippet doesn't make much sense. To make an NSMutableArray, do this:
NSMutableArray *array = [NSMutableArray array];
If you don’t need an order (normally you don’t), use a NSSet/NSMutableSet.

When to use enumerateObjectsUsingBlock vs. for

Besides the obvious differences:
Use enumerateObjectsUsingBlock when you need both the index and the object
Don't use enumerateObjectsUsingBlock when you need to modify local variables (I was wrong about this, see bbum's answer)
Is enumerateObjectsUsingBlock generally considered better or worse when for (id obj in myArray) would also work? What are the advantages/disadvantages (for example is it more or less performant)?
Ultimately, use whichever pattern you want to use and comes more naturally in the context.
While for(... in ...) is quite convenient and syntactically brief, enumerateObjectsUsingBlock: has a number of features that may or may not prove interesting:
enumerateObjectsUsingBlock: will be as fast or faster than fast enumeration (for(... in ...) uses the NSFastEnumeration support to implement enumeration). Fast enumeration requires translation from an internal representation to the representation for fast enumeration. There is overhead therein. Block-based enumeration allows the collection class to enumerate contents as quickly as the fastest traversal of the native storage format. Likely irrelevant for arrays, but it can be a huge difference for dictionaries.
"Don't use enumerateObjectsUsingBlock when you need to modify local variables" - not true; you can declare your locals as __block and they'll be writable in the block.
enumerateObjectsWithOptions:usingBlock: supports either concurrent or reverse enumeration.
with dictionaries, block based enumeration is the only way to retrieve the key and value simultaneously.
Personally, I use enumerateObjectsUsingBlock: more often than for (... in ...), but - again - personal choice.
For simple enumeration, simply using fast enumeration (i.e. a for…in… loop) is the more idiomatic option. The block method might be marginally faster, but that doesn't matter much in most cases — few programs are CPU-bound, and even then it's rare that the loop itself rather than the computation inside will be a bottleneck.
A simple loop also reads more clearly. Here's the boilerplate of the two versions:
for (id x in y){
}
[y enumerateObjectsUsingBlock:^(id x, NSUInteger index, BOOL *stop){
}];
Even if you add a variable to track the index, the simple loop is easier to read.
So when you should use enumerateObjectsUsingBlock:? When you're storing a block to execute later or in multiple places. It's good for when you're actually using a block as a first-class function rather than an overwrought replacement for a loop body.
Although this question is old, things have not changed, the accepted answer is incorrect.
The enumerateObjectsUsingBlock API was not meant to supersede for-in, but for a totally different use case:
It allows the application of arbitrary, non-local logic. i.e. you don’t need to know what the block does to use it on an array.
Concurrent enumeration for large collections or heavy computation (using the withOptions: parameter)
Fast Enumeration with for-in is still the idiomatic method of enumerating a collection.
Fast Enumeration benefits from brevity of code, readability and additional optimizations which make it unnaturally fast. Faster than a old C for-loop!
A quick test concludes that in the year 2014 on iOS 7, enumerateObjectsUsingBlock is consistently 700% slower than for-in (based on 1mm iterations of a 100 item array).
Is performance a real practical concern here?
Definitely not, with rare exception.
The point is to demonstrate that there is little benefit to using enumerateObjectsUsingBlock: over for-in without a really good reason. It doesn't make the code more readable... or faster... or thread-safe. (another common misconception).
The choice comes down to personal preference. For me, the idiomatic and readable option wins. In this case, that is Fast Enumeration using for-in.
Benchmark:
NSMutableArray *arr = [NSMutableArray array];
for (int i = 0; i < 100; i++) {
arr[i] = [NSString stringWithFormat:#"%d", i];
}
int i;
__block NSUInteger length;
i = 1000 * 1000;
uint64_t a1 = mach_absolute_time();
while (--i > 0) {
for (NSString *s in arr) {
length = s.length;
}
}
NSLog(#"For-in %llu", mach_absolute_time()-a1);
i = 1000 * 1000;
uint64_t b1 = mach_absolute_time();
while (--i > 0) {
[arr enumerateObjectsUsingBlock:^(NSString *s, NSUInteger idx, BOOL *stop) {
length = s.length;
}];
}
NSLog(#"Enum %llu", mach_absolute_time()-b1);
Results:
2014-06-11 14:37:47.717 Test[57483:60b] For-in 1087754062
2014-06-11 14:37:55.492 Test[57483:60b] Enum 7775447746
To answer the question about performance, I made some tests using my performance test project. I wanted to know which of the three options for sending a message to all objects in an array is the fastest.
The options were:
1) makeObjectsPerformSelector
[arr makeObjectsPerformSelector:#selector(_stubMethod)];
2) fast enumeration & regular message send
for (id item in arr)
{
[item _stubMethod];
}
3) enumerateObjectsUsingBlock & regular message send
[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
[obj _stubMethod];
}];
It turns out that makeObjectsPerformSelector was the slowest by far. It took twice as long as fast enumeration. And enumerateObjectsUsingBlock was the fastest, it was around 15-20% faster than fast iteration.
So if you're very concerned about the best possible performance, use enumerateObjectsUsingBlock. But keep in mind that in some cases the time it takes to enumerate a collection is dwarfed by the time it takes to run whatever code you want each object to execute.
It's fairly useful to use enumerateObjectsUsingBlock as an outer loop when you want to break nested loops.
e.g.
[array1 enumerateObjectsUsingBlock:^(id obj1, NSUInteger idx, BOOL * _Nonnull stop) {
for(id obj2 in array2) {
for(id obj3 in array3) {
if(condition) {
// break ALL the loops!
*stop = YES;
return;
}
}
}
}];
The alternative is using goto statements.
Thanks to #bbum and #Chuck for starting comprehensive comparisons on performance. Glad to know it's trivial. I seem to have gone with:
for (... in ...) - as my default goto. More intuitive to me, more programming history here than any real preference - cross language reuse, less typing for most data structures due to IDE auto complete :P.
enumerateObject... - when access to object and index is needed. And when accessing non-array or dictionary structures (personal preference)
for (int i=idx; i<count; i++) - for arrays, when I need to start on a non-zero index

Why has NSNumber such strange retainCounts?

NSNumber* n = [[NSNumber alloc] initWithInt:100];
NSNumber* n1 = n;
In the code above, why is the value of n's retainCount set to 2? In the second line of the code, I didn't use retain to increase the number of retainCount.
I found a strange situation. Actually the retainCount depends on the initial number:
NSNumber *n = [[NSNumber alloc] initWithInt:100];
// n has a retainCount of 1
NSNumber *n2 = [[NSNumber alloc] initWithInt:11];
// n has a retainCount of 2
Stop. Just stop. Never look at the retainCount of an object. Ever. It should never have been API and available. You're asking for pain.
There's too much going on for retainCount to be meaningful.
Based on this link here, it's possible that there's some optimization going on under the covers for common NSNumbers (which may not happen in all implementations hence a possible reason why #dizy's retainCount is 1).
Basically, because NSNumbers are non-mutable, the underlying code is free to give you a second copy of the same number which would explain why the retain count is two.
What is the address of n and n1? I suspect they're the same.
NSNumber* n = [[NSNumber alloc] initWithInt:100];
NSLog(#"Count of n : %i",[n retainCount]);
NSNumber* n1 = n;
NSLog(#"Count of n : %i",[n retainCount]);
NSLog(#"Count of n1: %i",[n1 retainCount]);
NSLog(#"Address of n : %p", n);
NSLog(#"Address of n1: %p", n1);
Based on your update, that link I gave you is almost certainly the issue. Someone ran a test and found out that the NSNumbers from 0 to 12 will give you duplicates of those already created (they may in fact be created by the framework even before a user requests them). Others above 12 seemed to give a retain count of 1. Quoting:
From the little bit of examination I've been able to do, it looks as if you will get "shared" versions of integer NSNumbers for values in the range [0-12]. Anything larger than 12 gets you a unique instance even if the values are equal. Why twelve? No clue. I don't even know if that's a hard number or circumstantial.
Try it with 11, 12 and 13 - I think you'll find 13 is the first to give you a non-shared NSNumber.
Retain counts are an implementation detail. They can be kindasorta useful in debugging, sometimes, but in general you should not care about them. All you should care about is that you're following the memory management rules.
For an example of why looking at retain counts is unreliable, this is a perfectly legal class that obeys the API contract and will behave correctly in all circumstances:
#implementation CrazyClass
- (id)retain {
for(int i=0; i<100; i++) {
[super retain];
}
}
- (void)release {
for(int i=0; i<100; i++) {
[super release];
}
}
#end
…but if you inspected its retain count, you'd think you had an "issue."
This precise case doesn't happen too often in practice, but it illustrates why looking at retain counts is useless for telling if something is wrong. Objects do get retained behind the scenes by code outside of your control. NSNumber, for example, will sometimes cache instances. Objects get autoreleased, which isn't reflected in the retain count. Lots of things can happen that will confuse the retain count. Some classes might not even keep their retain counts where you can see them.
If you suspect you have a leak, you should check with the real debugging tools meant for that purpose, not by poking at retain counts. And for code you're writing, you should primarily be concerned with following the guidelines I linked above.
You should never rely on the retainCount of an object. You should only use it as a debugging aid, never for normal control flow.
Why? Because it doesn't take into account autoreleases. If an object is retained and subequently autoreleased, its retainCount will increment, but as far as you're concerned, its real retain count hasn't been changed. The only way to get an object's real retain count is to also count how many times it's been added to any of the autorelease pools in the autorelease pool chain, and trying to do so is asking for trouble.
In this case, the retainCount is 2 because somewhere inside alloc or initWithInt:, the object is being retained and autoreleased. But you shouldn't need to know or care about that, it's an implementation detail.
I think you have something else going on...
NSNumber* n = [[NSNumber alloc] initWithInt:100];
NSNumber* n1 = n;
NSLog(#"n = %i",[n retainCount]);
Result is 1
There is however a fly in this ointment. I've seen crashes due to retain count overflows from NSNumber instances containing small integers. In large systems that run for a very long time you can exceed the max int and get an Internal Consistancy error.
NSInternalInconsistencyException: NSIncrementExtraRefCount() asked to increment too far for <NSIntNumber: 0x56531f7969f0> - 0