Objective-C Fast Enumeration Bubble Sort - objective-c

I'm trying to integrate some GCD into my code, and have found that a severe bottleneck is a bubble comparison I am performing between objects in a large array. Here is the original code:
NSUInteger count = [arrayToDoWorkOn count];
for (int i = 0; i < count; i++)
{
for (int j = i + 1; j < count; j++)
{
[[arrayToDoWorkOn objectAtIndex:i] compare:[arrayToDoWorkOn objectAtIndex:j]];
}
}
Get my drift? So a lot of other fast enumeration tasks can be easily GCD'd by converting
for (id obj in array)
{
[obj aMessage:stuff];
}
to:
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
[obj aMessage:stuff];
}];
Is there a way to convert my look-ahead-sorta-bubble-sorta-algorithm-thing to something that I can feed to a GCD block implementation?

I wouldn't recommend implementing your own sort if NSArray already has a built in method for it that will most likely sort faster than anything you can come up with. You can just use this:
NSArray *sortedArray = [arrayToDoWorkOn sortedArrayWithComparator:^(id firstObject, id secondObject) {
/* comparison code (e.g. return [[firstObject title] compareTo:[secondObject title]], or something) */
}];
Now, if you need to use the objects during the sort, you're in for a pickle, but I'd recommend looking into sorts more efficient than a bubble sort (quick sort is a pretty good one).
Besides this, I think you're a bit confused about GCD. Writing and using a block does not inherently execute it with GCD; that has to be done manually (strictly speaking, a block is simply a collection of lines of code and does not inherently have anything to do with GCD; GCD simply uses blocks for execution). NSArray's enumerateObjectsUsingBlock: method most likely does not use GCD to enumerate the array (at least the reference gives no insight on this, so please prove me wrong), and if it does, it's not because you're supplying it with a block, but rather because that's how Apple chose to implement it. Most methods taking blocks do not use GCD to execute them.
I recommend you read the Grand Central Dispatch (GCD) Reference as well as Cocoa Samurai's A Guide to Blocks and GCD to get greater insight into the specifics of the topic.

Related

NSMutableDictionary much slower than Java Map... why?

The following code, which maps simple value holders to an object, runs over 15x faster in Java than Objective-C using XCode 7 beta3, "Fastest, Aggressive Optimizations [-Ofast]". I can get over 280M lookups/sec in Java but only about 19M in the objc example. (I posted the corresponding Java code here as this started as a Swift comparison: Swift Dictionary slow even with optimizations: doing uncessary retain/release?).
This is a simplified version of my real code which is definitely bound by hash lookup time and exhibits this overall performance difference as well. In the test below I'm testing the value for null just to make sure the compiler doesn't optimize away the lookup, but in the real app I'd be using the value in most cases.
When I look at instruments I see a lot of time spent in retain / release, msgSend, and some locking calls that I don't understand.
Any ideas on what could account for this being 10-15x slower than Java or any workarounds would be appreciated. I can actually implement a perfect hash like the one below so I could use a fast int-object dictionary for iOS if I could find one.
#interface MyKey : NSObject <NSCopying>
#property int xi;
#end
#implementation MyKey
- (NSUInteger)hash { return self.xi; }
- (BOOL)isEqual:(id)object { return ((MyKey *)object).xi == self.xi; }
- (id)copyWithZone:(NSZone *)zone { return self; }
#end
NSMutableDictionary *map = [NSMutableDictionary dictionaryWithCapacity:2501];
NSObject *obj = [[NSObject alloc] init];
int range = 2500;
for (int x=0; x<range; x++) {
MyKey *key = [[MyKey alloc] init];
key.xi=x;
[map setObject:obj forKey:key];
}
MyKey *key = [[MyKey alloc] init];
int runs = 50;
for (int run=0; run<runs; run++)
{
NSDate *start = [NSDate date];
int reps = 10000;
for(int rep=0; rep<reps; rep++)
{
for (int x=0; x<range; x++) {
key.xi=x;
if ( [map objectForKey:key] == nil ) { NSLog(#"missing key"); }
}
}
NSLog(#"rate = %f", reps*range/[[NSDate date] timeIntervalSinceDate:start]);
}
You could reimplement your -isEqual: method like this to avoid property accessors:
- (BOOL) isEqual:(id)other
{
return _xi == ((MyKey*)other)->_xi;
}
That would not be acceptable if your MyKey class might be subclassed, but I see from the Java code that the class there is final.
The computational complexity of the NSMutableDictionary is the next (from CFDictionary.h file):
The access time for a value in the dictionary is guaranteed to be at
worst O(N) for any implementation, current and future, but will
often be O(1) (constant time). Insertion or deletion operations
will typically be constant time as well, but are O(N*N) in the
worst case in some implementations. Access of values through a key
is faster than accessing values directly (if there are any such
operations). Dictionaries will tend to use significantly more memory
than a array with the same number of values.
Means, almost all the time you should have O(1) complexity for access/insertion/deletion. For Java HashMap you should get pretty much the same.
According to this research there are no benefits in using dictionaryWithCapacity: convenience initializer.
In case you use integer as a key, probably it would be possible to replace dictionary with array.
In this WWDC session they explained objc_msgSend performance issues and how to deal with them.
The first solution is to use C++ and STL containers. The second one is to use Swift, because unlike Objective-C it is only dynamic when it notes to be.

Objective-c pendulum modelling memory issues

I am trying to implement a modelling class for a Physics project with finite difference methods for simulating a simple pendulum. I want to be able to make this class as generic as possible so I can do whatever I want with the values on each iteration of the method. For this reason I have given my methods callback blocks which can also be used to stop the method if we want to.
For example my Euler method loop looks like so:
for (NSInteger i = 0; i < n; i++) {
if (callBack) {
if(!callBack(NO, currentTheta, currentThetaDot, currentT, (CGFloat)i/n)) break;
}
currentTheta += self.dt*f_single_theta(currentThetaDot);
currentThetaDot += self.dt*f_single_thetaDot(currentTheta, currentThetaDot, gamma);
currentT += self.dt;
}
And in the callBack block I run the code
^BOOL (BOOL complete, double theta, double thetaDot, CGFloat timeElapsed, CGFloat percentComplete){
eulerT = [eulerT stringByAppendingFormat:#"%.8f\n",timeElapsed];
eulerTheta = [eulerTheta stringByAppendingFormat:#"%.8f\n",theta];
if ((currentThetaDot*currentThetaDot + cos(currentTheta)) > 0.5) {
return 0; // stops running if total E > 0.5
}
return 1;
}];
Where eulerT and eulerTheta are strings which I later save to a file. This callback method quickly results in a massive build up of memory, even for n of order 10,000 I end up with about 1Gb of RAM usage. As soon as I comment out calling the callBack block this drops right off. Is there anyway I can keep this nice functionality without the massive memory problems?
Many people who are new to Objective C do not realize the difference between [NSArray array] and [[NSArray alloc] init]. In the days before ARC, the difference was much more obvious now. Both create a new object, but the former allocates the object, assigns it to the current NSAutoreleasePool, and leaves it with a retain count of 0 while the latter allocates it and leaves it with a retain count of 1.
Objects that are assigned to an NSAutoreleasePool do not get deallocated immediately when the retain count reaches 0. Instead, they get deallocated when the OS gets time to. Generally this can be assumed to be when control returns to the current run loop, but it can also be when drain is called on the NSAutoreleasePool.
With ARC, the difference is less obvious, but still significant. Many, if not most, of the objects your allocate are assigned to an autorelease pool. This means that you don't get them back just because you're done using them. That leads to the memory usage spiking in tight loops, such as what you posted. The solution is to explicitly drain your autorelease pool, like this:
for (NSInteger i = 0; i < n; i++) {
if (callBack) {
#autoreleasepool {
if(!callBack(NO, currentTheta, currentThetaDot, currentT, (CGFloat)i/n))
break;
}
}
currentTheta += self.dt*f_single_theta(currentThetaDot);
currentThetaDot += self.dt*f_single_thetaDot(currentTheta, currentThetaDot, gamma);
currentT += self.dt;
}
You should wrap the inside of your loop in #autoreleasepool{} to clean up temporary objects.

How do Objective-C comparison blocks know their arguments for the sortUsingComparator method?

I'm in the process of learning Objective-C, and am trying to get my head wrapped around the idea of using blocks.
In an example I'm seeing, there is a method meant to sort an NSArray named book in alphabetical order by name:
-(void) sort
{
[book sortUsingComparator:
^(id obj1, id obj2) {
return [[obj1 name] compare: [obj2 name]];
} ];
}
How does the method pass the objects to the obj1 and obj2 parameters? Does the sortUsingComparator somehow automatically pass 2 objects to its comparator?
sortUsingComparator: iterates over the array and calls the block with various pairs of objects to determine how to sort them. There's no magic here — it's a normal sorting function, but it uses your block instead of > to compare the values.
Well, depending on the implementation of the sort, every time the sort algorithm needs to compare 2 elements this will get called. You don't really need to know what will get passed to it, just define an order relationship for the types that get passed. It'll ask what he needs to know.
Some extra information about blocks that answers your question, a block can be assigned to a variable and called like a function. The sortUsingComparator: method signature is:
- (void)sortUsingComparator:(NSComparator)cmptr
cmptr is the variable that holds your block. The sortUsingComparator: method will run every element in the array through its sort algorithm and, as Fernando pointed out, every time the sort algorithm needs to compare 2 elements it's called like this:
NSComparisonResult result = cmptr(obj1, obj2);
And your block code is executed. So the answer to your question:
Does the sortUsingComparator somehow automatically pass 2 objects to its comparator?
is yes :)
The sort method does something like this (I'm not claiming the sort: method does this exactly, but the idea remains):
for (i = 0; i < [book count]; i++) {
id currentObject = [book objectAtIndex:i]; // obj1
for (j = 0; j < i; j++) {
id sortedObject = [book objectAtIndex:j]; // obj2
NSComparisonResult result = sortBlock(currentObject, sortedObject);
// Insert currentObject where appropriate; perform the rest of the sort
}
}
In this case, I'm assuming that the block's parameter name is ^sortBlock (the caret denotes a block). You invoke blocks just like regular functions, with parentheses and arguments.
So to answer your question…it's automatic in the sense that you don't have to think about it, but there's no magic going on.
Hope this helps!

comparing arrays in objective-c

Ok a pretty simple question.. in c++ it seems to work but in objective-c i seem to struggle with it :S ..
If you want to compare two arrays it should be something like this right
for ( int i = 0; i < [appdelegate.nicearray count]; i++ )
{
if ( appdelegate.nicearray[i] == appdelegate.exercarray[i] )
{
NSLog(#"the same elements in this selection");
}
}
what's the problem exactly ?
These are Cocoa array objects (instances of NSArray), not C arrays or C++ vectors, and remember that Objective-C does not have operator overloading. The only things you can do with an object are pass it around, store it in variables, and send messages to it.
So the array-subscript operator is wrong with Objective-C objects. I don't think it's even linguistically valid to dereference a pointer to an Objective-C object, so this code should be giving you a compiler error. I may be misremembering, though. If it does make it to runtime, that code will crash sooner or later, since you're accessing memory beyond the ends of the array objects.
(EDIT from the year 2013: Objective-C now supports subscripting of objects. This ultimately translates into the appropriate objectAtIndex: or replaceObjectAtIndex:withObject: message. So, the code in the question would actually work now, although it's still not the proper way to simply walk an array, much less to compare two arrays.)
The proper way to retrieve an object from an NSArray object by its index is not to use the array-subscript operator, but to send the array object the objectAtIndex: message:
[myArray objectAtIndex:i]
The proper way to iterate on the elements of an array object, assuming you don't really need the index for something else (such as replacing objects in a mutable array), is to loop on it directly (this is called “fast enumeration”):
for (MyObject *myObject in myArray) {
…
}
NSArray also responds to objectEnumerator and reverseObjectEnumerator, which return a similarly-iterable object. Of the two, reverseObjectEnumerator is the more useful in new code, since you can just iterate on the array directly to iterate forward. Both of them were most useful before fast enumeration existed; that code looked like this:
NSEnumerator *myArrayEnum = [myArray objectEnumerator];
MyObject *myObject;
while ((myObject = [myArrayEnum nextObject])) {
…
}
(Yes, that's an assignment in the condition. Deliberately, hence the extra (). We coded boldly back then, didn't we?)
For what you're doing, though, you more likely want to send one of the arrays an isEqualToArray: message, as Williham Totland suggested:
BOOL theyAreEqual = [myFirstArray isEqualToArray:mySecondArray];
This will make sure both arrays have the same length, then walk them both in lock-step, sending isEqual: to each pair of objects. It'll return YES if every isEqual: message returned YES; NO otherwise. The arrays may contain different objects, but as long as each pair is equal, the arrays themselves are equal.
That assumes you want object equality. Two separate objects are equal if one of them responds with YES when you send it an isEqual: message and pass the other object. If you meant to compare the identities of the objects, then you do need to do the lock-step loop yourself and use ==:
BOOL arraysContainTheSameObjects = YES;
NSEnumerator *otherEnum = [otherArray objectEnumerator];
for (MyObject *myObject in myArray) {
if (myObject != [otherEnum nextObject]) {
//We have found a pair of two different objects.
arraysContainTheSameObjects = NO;
break;
}
}
But that's unlikely. Most of the time, I have wanted to test the objects' equality, not identities, so isEqualToArray: is what I wanted.
You want the isEqualToArray: method. As in:
if ([arrayOne isEqualToArray:arrayTwo]) {
// Do something
}
This will recursively compare the two arrays, while having the advantage of not being needlessly circuitous and not requiring a loop.
Try telling us the result you're getting when you run this code. The approach is correct, but try this one:
for (int i =0; i< appdelegate.nicearray.count; i++)
{
if ([[appdelegate objectAtIndex:i] isEqual: [appdelegate.exercarray objectAtIndex:i]])
{
NSLog(#"the same");
}
}
Here's a little one I put together based on the top ranked example. This merely checks that the arrays contains the same values, irrespective of order and if there are any duplicates. I mainly use this to compare keys of two dictionaries (which often return their allKeys arrays in various sort orders) to see if they contain the same objects. Thanks Peter Hosley for providing the example I adapted this from.
#pragma mark - Arrays
// Check to see if arrays contain the same elements, not necessarily in the same order
// This is different from [array isEqualToArray:responseKeys] which demands the same order in both arrays
// ## Does not compensate for duplicate entries in an array
+ (BOOL)doArraysContainTheSameObjects:(NSArray *)firstArray withArray:(NSArray *)secondArray {
BOOL arraysContainTheSameObjects = YES;
for (id myObject in firstArray) {
if (![secondArray containsObject:myObject]) {
// We have found an object that is not in the other array.
arraysContainTheSameObjects = NO;
break;
}
}
return arraysContainTheSameObjects;
}
I do the following when comparing arrays:
Check to see if any of the arrays are nil when the other is not
Check to see if the lengths are the same
Iterate (using a for loop like you have) over each element checking the matching element in the other array.
To compare elements you need to define what you want to regard as being "equal". Are they equal only if the pointers in the array are equal or can they be equal if the content is equal too.
For the pointer case, you can use ==.
For the deep comparison you might need to use CompareTo or something similar.

Is there an easy way to iterate over an NSArray backwards?

I've got an NSArray and have to iterate over it in a special case backwards, so that I first look at the last element. It's for performance reasons: If the last one just makes no sense, all previous ones can be ignored. So I'd like to break the loop. But that won't work if I iterate forward from 0 to n. I need to go from n to 0. Maybe there is a method or function I don't know about, so I wouldn't have to re-invent the wheel here.
To add on the other answers, you can use -[NSArray reverseObjectEnumerator] in combination with the fast enumeration feature in Objective-C 2.0 (available in Leopard, iPhone):
for (id someObject in [myArray reverseObjectEnumerator])
{
// print some info
NSLog([someObject description]);
}
Source with some more info: http://cocoawithlove.com/2008/05/fast-enumeration-clarifications.html
Since this is for performace, you have a number of options and would be well advised to try them all to see which works best.
[array enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:…]
-[NSArray reverseObjectEnumerator]
Create a reverse copy of the array and then iterate through that normally
Use a standard C for loop and start and work backwards through the array.
More extreme methods (if performance is super-critical)
Read up on how Cocoa implements fast object enumeration and create your own equivalent in reverse.
Use a C or C++ array.
There may be others. In which case, anyone feel free to add it.
From here:
NSEnumerator* myIterator = [myArray reverseObjectEnumerator];
id anObject;
while( anObject = [myIterator nextObject])
{
/* do something useful with anObject */
}
[NsArray reverseObjectEnumerator]
for (int i = ((int)[array count] - 1); i > -1; i--) {
NSLog(#"element: %#",array[i]);
}