« April 2006 | Main | July 2006 »

May 2006 Archives

May 5, 2006

NSCFBoolean hashes incorrectly

What a giant clusterfuck that is.

Here's what NSObject isEqual: dictates about the relationship between -hash and -isEqual:

If two objects are equal, they must have the same hash value. This last point is particularly important if you define isEqual: in a subclass and intend to put instances of that subclass into a collection. Make sure you also define hash in your subclass.

That's the meat and potatoes right there. And this is what happens on 10.4.5.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
   NSAutoreleasePool *pool;
   NSNumber   *a;
   NSNumber   *b;
   
   pool = [NSAutoreleasePool new];
   
   a = [NSNumber numberWithInt:1];
   b = [NSNumber numberWithBool:YES];
   
   NSLog( @"a=%@ (@%p hash=$%X), b=%@ (@%p hash=$%X), [a isEqual:b] == %s",
          a, a, [a hash], 
          b, b, [b hash],
          [a isEqual:b] ? "YES" : "NO");
   
   [pool release];
   return( 0);
}
2006-05-05 12:22:42.800 NSCFBooleanClusterFuck[1673] a=1 (@0x303280 hash=$1), 
b=1 (@0xa073a95c hash=$A073A95C), [a isEqual:b] == YES
NSCFBoolean chooses to inherit the hash from NSObject.

As my customer is running 10.4.6 and noticed the problem, I am pretty sure the same problem is alive and well today.

May 6, 2006

Simple fix for NSCFBoolean hash problem

A simple fix for this problem is a category on NSCFBoolean. NSCFBoolean is a hidden class, so we have to define the interface ourselves, as we want to put a category on it. Because we don't access instance variables, it really doesn't matter that this may not be the correct interface as defined by Apple. (But it is, at least according to classdump.)
#import <Foundation/Foundation.h>


@interface NSCFBoolean : NSNumber // could ignore inheritance, but less warnings this way
{
}
@end


@interface NSCFBoolean ( MulleFixHash)

- (unsigned int) hash;

@end


@implementation NSCFBoolean ( MulleFixHash)

- (unsigned int) hash
{
   return( [self unsignedIntValue]);
}

@end


int main (int argc, const char * argv[])
{
   NSAutoreleasePool *pool;
   NSNumber   *a;
   NSNumber   *b;
   
   pool = [NSAutoreleasePool new];
   
   a = [NSNumber numberWithInt:0];
   b = [NSNumber numberWithBool:NO];
   
   NSLog( @"%@ a=%@ (@%p hash=$%X)",
          [a class], a, a, [a hash]);
   NSLog( @"%@ b=%@ (@%p hash=$%X)",
          [b class], b, b, [b hash]);
   NSLog( @"[a isEqual:b] == %s",
          [a isEqual:b] ? "YES" : "NO");
   
   [pool release];
   return( 0);
}
2006-05-06 22:04:49.285 NSCFBooleanHash[1115] NSCFNumber a=0 (@0x303260 hash=$0)
2006-05-06 22:04:49.285 NSCFBooleanHash[1115] NSCFBoolean b=0 (@0xa07c1964 hash=$0)
2006-05-06 22:04:49.285 NSCFBooleanHash[1115] [a isEqual:b] == YES

May 11, 2006

xcodebuild drives me nuts, or is it the unix shell ?

I want to pass OTHER_CFLAGS into the build system. xcodebuild "OTHER_CFLAGS=-DFOO=1" works nicely. My problem is that I don't want FOO to be a number, I want it to be a string. It's not a problem of gcc, it can do it
aden:/tmp nat$ cat main.c
main()
{
   printf( "%s\n", FOO);
}
aden:/tmp nat$ cc -w -DFOO='"VfL Bochum"' main.c -o main ; ./main
VfL Bochum
But I can't get xcodebuild to preserve the quoting no matter how I try.

May 25, 2006

MulleSybaseEOAdaptor 2.7 Releasenotes

The last public release was 2.3 so here's what has happened in the mean time

Version 2.7

  1. Speed up of mulleSybaseRowDictionary read access to post-insane levels.

Version 2.6

  1. Fix uninitalized factory problem, introduced in 2.4 by reuse of bindInfos.
  2. "Working with Custom Data Types". MulleSybaseEOAdaptor adheres now closer to specs.

Version 2.5

  1. Handle NSNull if available. NSNull and EONull are considered to be equivalent. The adaptor will only return EONull from fetched data though.

Version 2.4

  1. Fixed a datetime handling bug when the server timeZone was not set. This manifests in Tiger 10.4.
  2. Changed the way the adaptor advertises its binding requirements.
  3. Fixed a possibly crashing double free in image/text handling
  4. Fixed a little leak with error messages.
  5. Reuses bindInfos. This has the benefit of less memory fragmentation and being a bit faster.

May 28, 2006

MulleEOInterface 1.0 Releasenotes

The number of changes are just sickening :) I tried to keep the GNUMakefile in sync, but maybe I failed doing so.

Version 1.0

  1. EOPickTextAssociation uses case insensitive like as a fall back default.
  2. EOTextAssociation clears the display object on connection, which appears to be historically correct.
  3. EOPopUpBoxAssociations and EOComboboxAssociations sort their contents automatically . This is a feature that will likely be undone or modified in 2.0. But for now it's historically correct apparently.
  4. NSPopUpBox hate, hate, hate. I have changed EOAssociation PopUpBox support and subsequently EOPopUpBoxAssociation to now use a helper data structure. All this because NSPopUpBox has an incredibly stupid API.
  5. Changed updateDisplayedObjects to always clear indexes if objects did change.
  6. EOTextAssociation updates now more agressively. This can be turned off, which I would suggest to do, if the text edited is large.
  7. EOColumnAssociation and EOAssociation are now binary compatible (again) with the original classes.
  8. Added an intermediate class EODisplayGroupAssociation. This class receives the EODisplayGroupShutdownNotification and nils out the internal reference, which is necessary to avoid spurious crashes.
  9. Again fiddled around with action: for the NSTextField special case.
  10. EOMasterDetailAssociation creates EODetailDataSources if missing from the EODisplayGroup, which is more compatible.
  11. EODisplayGroup forces selectionChanged: message, even if the delegate doesn't want the selection. This way the UI and the DG stay in sync.
  12. Optimistic Refresh now serializes compatibly with original EOF. You need to recheck your NIBs for this.
  13. Renamed displayGroup:shouldRedisplayForChangesInEditingContext: to displayGroup:shouldRedisplayForChangesInEditingContextNotification:, which is correct.
  14. Added an intermediate class EOColumnAssociationProxy. This class notices when the NSTableColumn goes away and breaks the connection on its EOColumnAssociation and nils out the object reference. For compatibility this proxy forwards most messages to it's EOColumnAssociation. EOTableViewAssociation is now agnostic of the tricks EOColumnAssociation plays with NSTableColumn. Class methods +[EOColumnAssociation columnAssociationsForTableView:] and +[EOColumnAssociation *columnAssociationForTableColumn:] are used.
  15. forces initial sync with EODisplayGroup on establishConnection
  16. EOGenericControl initializes "lastValue" correctly in establishConnection.
  17. Coded EORadioMatrixAssociation.
  18. Started coding EOMatrixAssociation but gave up because of sudden NSMatrix hate. The damn thing grows upwards!
  19. EODisplayGroup now respects selectsFirstObjectAfterFetch a bit more than before.
  20. Coded something more useful for EOMasterPeerAssociation, though it hasn't been tested at all.
  21. Conveniently added -[EOFault isFault] check in setObjectsArray: speeds up EODisplayGroup in real life dramatically.
  22. Contrary to specification "object" is now retained during the established phase of the Association, with some notable exceptions being the EODisplayGroupAssociations and EOColumnAssociation.
  23. In QueryMode ValueForKey operations use valueForKey instead of valueForKeyPath

May 31, 2006

Xcode is getting on my nerves

I have about 12 projects open, and Xcode just doesn't seem to be able to handle it.

Every time Xcode spins my G5 gets really agitated and noisy. Is 4-Ghz nowadays too slow ?

Really obscure Foundation (was EOControl) bug

This curious bug will probably only hit those, who write KVC caching schemes. Which means on this planet, this will just interest me, Helge and some unknown guy at Apple :) Sane people don't use same-named instance variables with underscore and without. The bug is, that takeValueForKey: has a different sequence of accessing ivars than valueForKey:.
#import <Foundation/Foundation.h>

@interface Foo : NSObject
{
   id   bar;
   id   _bar;
}
@end


@implementation Foo

- (NSString *) description
{
   return( [NSString stringWithFormat:@"bar=\"%@\"/_bar=\"%@\"", bar, _bar]);
}

@end


static void   test( NSString *storeKey, NSString *queryKey)
{
   Foo   *foo;
   
   foo = [[Foo new] autorelease];
   [foo takeValue:@"VfL Bochum"
           forKey:storeKey];
   NSLog( @"tvfk:\"%@\"+vfk:\"%@\"=%@ (%@)", storeKey, queryKey, [foo valueForKey:queryKey], foo);
   
   foo = [[Foo new] autorelease];
   [foo takeStoredValue:@"VfL Bochum"
                 forKey:storeKey];
   NSLog( @"tsvfk:\"%@\"+vfk:\"%@\"=%@ (%@)", storeKey, queryKey, [foo valueForKey:queryKey], foo);
   
   foo = [[Foo new] autorelease];
   [foo takeValue:@"VfL Bochum"
           forKey:storeKey];
   NSLog( @"tvfk:\"%@\"+svfk:\"%@\"=%@ (%@)", storeKey, queryKey, [foo storedValueForKey:queryKey], foo);
   
   foo = [[Foo new] autorelease];
   [foo takeStoredValue:@"VfL Bochum"
                 forKey:storeKey];
   NSLog( @"%tsvfk:\"%@\"+svfk:\"%@\"=%@ (%@)", storeKey, queryKey, [foo storedValueForKey:queryKey], foo);
}

int main (int argc, const char * argv[]) 
{
   NSAutoreleasePool *pool;
   
   pool = [NSAutoreleasePool new];
   
   test( @"bar", @"bar");
   test( @"bar", @"_bar");
   test( @"_bar", @"bar");
   test( @"_bar", @"_bar");
   
   [pool release];
   return( 0);
}
2006-05-31 01:26:53.902 KVCTest[19582] tvfk:"bar"+vfk:"bar"=(null) (bar="VfL Bochum"/_bar="(null)")
not getting the value back you put in under the same name is not cool
2006-05-31 01:26:53.903 KVCTest[19582] tsvfk:"bar"+vfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.903 KVCTest[19582] tvfk:"bar"+svfk:"bar"=(null) (bar="VfL Bochum"/_bar="(null)")
2006-05-31 01:26:53.904 KVCTest[19582] tsvfk:"bar"+svfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.904 KVCTest[19582] tvfk:"bar"+vfk:"_bar"=(null) (bar="VfL Bochum"/_bar="(null)")
2006-05-31 01:26:53.904 KVCTest[19582] tsvfk:"bar"+vfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.904 KVCTest[19582] tvfk:"bar"+svfk:"_bar"=(null) (bar="VfL Bochum"/_bar="(null)")
2006-05-31 01:26:53.904 KVCTest[19582] tsvfk:"bar"+svfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tvfk:"_bar"+vfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tsvfk:"_bar"+vfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tvfk:"_bar"+svfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tsvfk:"_bar"+svfk:"bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tvfk:"_bar"+vfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tsvfk:"_bar"+vfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tvfk:"_bar"+svfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")
2006-05-31 01:26:53.905 KVCTest[19582] tsvfk:"_bar"+svfk:"_bar"=VfL Bochum (bar="(null)"/_bar="VfL Bochum")

About May 2006

This page contains all entries posted to Nat!'s Web Journal in May 2006. They are listed from oldest to newest.

April 2006 is the previous archive.

July 2006 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.34