Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

mdeh

macrumors 6502
Original poster
Jan 3, 2009
345
2
Hi all,
Following along in the documentation using "sortedArrayUsingFunction", I cannot seem to to be able to get the Array to sort as I expect.
So, here is the code...in a command line ap for simplicity. I would have expected the last 2 sorts to be inverse of the other, but both sorts are the same.
I **think** I have pretty carefully copied the examples from the docs...so would really like to get some insight.

Thanks as always.



Code:
#import <Foundation/Foundation.h>


NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
	if (( NSInteger *) reverse == NO)
	{
		return [string2 localizedCaseInsensitiveCompare:string1];
	}
	
		return [string1 localizedCaseInsensitiveCompare:string2];
	
}

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	NSMutableArray *anArray =
    
	[NSMutableArray arrayWithObjects:@ "i", @"a", @"d", @"b",   @"c",  @"e",@"g",@"L", nil];
	
	NSLog(@"anArray:%@", anArray);
	
	
	
	
	NSArray *sortedArray;
	
	int reverseSort = NO;
	
	sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
	NSLog(@"Sort using function: \"NO\" %@", sortedArray);

	
	reverseSort = YES;
	
	sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
	NSLog(@"Sort using function:\"YES\" %@", sortedArray);
	
	
	
    [pool drain];
    return 0;
}

output:

2010-03-18 10:37:45.268 SortFun[2574:a0f] anArray:
i,
a,
d,
b,
c,
e,
g,
L
)
2010-03-18 10:37:45.273 SortFun[2574:a0f] Sort using function: "NO" (
a,
b,
c,
d,
e,
g,
i,
L
)
2010-03-18 10:37:45.273 SortFun[2574:a0f] Sort using function:"YES" (
a,
b,
c,
d,
e,
g,
i,
L
)
 
You pass the address of an int, accept it as void *, the cast to an NSInteger *, then compare it to YES and NO without dereferencing. I think a dereference would fix it, but also make the types agree. NSInteger won't always be typedef'd to int.

-Lee
 

Congratulation, you found a bug in Apple's code.

I tried compiling and running their code as given, and it produces the desired output (sorted in ascending order, not reversed), but it does so for the wrong reasons.

A simple test case to show the bug: change reverseSort to YES, recompile and rerun, and the same ascending-order output is produced.

There are several bugs in Apple's code, which combine to give the appearance of correctness:
1. the reverseSort flag is passed by reference, i.e. a pointer, but the void* received by the function is not dereferenced, i.e. the pointer itself is compared to NO, not the value pointed to.
2. the conditional logic in the sort-ordering function is inverted.

The same bug(s) occurs in other samples on the web page, although with Bool pointer.

There is a feedback form at the bottom of Apple's web page. I suggest sending them feedback that their example is wrong, and describe why. You can point them to this MacRumors thread.

Here's a simple way to start fixing your posted code:
Code:
NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
	int reverseSort = * ((int*)reverse);
	if (reverseSort)
...
This fixes both bugs: 1. it dereferences the pointer to get the flag, 2. it uses the correct sort-ordering logic (reverseSort non-zero produces a reversed sort).

You could also simplify the code to pass an actual YES/NO flag, rather than by reference. This will need a type-cast when invoking the sorting method, and a corresponding change in the sort-ordering function.
 
It definitely seems wrong to me:
Code:
#import <Foundation/Foundation.h>


NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
	if ((*(int *) reverse) == NO)
	{
		return [string2 localizedCaseInsensitiveCompare:string1];
	}
	
		return [string1 localizedCaseInsensitiveCompare:string2];
	
}

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

	NSMutableArray *anArray =
    
	[NSMutableArray arrayWithObjects:@ "i", @"a", @"d", @"b",   @"c",  @"e",@"g",@"L", nil];
	
	NSLog(@"anArray:%@", anArray);
	
	
	
	
	NSArray *sortedArray;
	
	int reverseSort = NO;
	
	sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
	NSLog(@"Sort using function: \"NO\" %@", sortedArray);

	
	reverseSort = YES;
	
	sortedArray = [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
	NSLog(@"Sort using function:\"YES\" %@", sortedArray);
	
	
	
    [pool drain];
    return 0;
}

I think with that change (i didn't test it) it should work.

-Lee
 
I think with that change (i didn't test it) it should work.

-Lee

Yep..it does. Rare to find an issue in the docs...I bet it has been there for years.

Thanks Lee...I knew I could rely on you!!!
:):)
 
Congratulation, you found a bug in Apple's code.

They should send you an iTunes gift-card or something every time you find a bug. Or run it like Chucky-Cheese where you bank up your tickets and can buy bigger/better prizes the more you have. Save up 500 tickets and you get your own personal official Apple objective-c oompa-loompa.
 
Yep..it does.

Just to clarify, but Lee's code still has the conditional-logic in the function inverted.

Sample output:
Code:
2010-03-18 13:59:30.454 a.out[8082] anArray:(i, a, d, b, c, e, g, L)
2010-03-18 13:59:30.470 a.out[8082] Sort using function: "NO" (L, i, g, e, d, c, b, a)
2010-03-18 13:59:30.470 a.out[8082] Sort using function:"YES" (a, b, c, d, e, g, i, L)

The one labeled "NO" should be ascending order, but it's descending. And vice versa for the one labeled "YES".

To fix it:
Code:
NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
	if ((*(int *) reverse))
 
Just to clarify, but Lee's code still has the conditional-logic in the function inverted.

Sample output:
Code:
2010-03-18 13:59:30.454 a.out[8082] anArray:(i, a, d, b, c, e, g, L)
2010-03-18 13:59:30.470 a.out[8082] Sort using function: "NO" (L, i, g, e, d, c, b, a)
2010-03-18 13:59:30.470 a.out[8082] Sort using function:"YES" (a, b, c, d, e, g, i, L)

The one labeled "NO" should be ascending order, but it's descending. And vice versa for the one labeled "YES".

To fix it:
Code:
NSInteger alphabeticSort(id string1, id string2, void *reverse)
{
	if ((*(int *) reverse))


Thanks Chown
I guess you should be getting the iTunes gift card!!!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.