diff --git a/ChangeLog b/ChangeLog index 209e8b8af..d3c4858c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,18 @@ +2010-02-08 Richard Frith-Macdonald + + * Source/NSAttributedString.m: minor cosmetic change + * Source/GSAttributedString.m: Re-introduce proxy for -string + and comment to try to avoid it being accidentally removed again. + * Source/GSString.m: Fixups to work properly with string proxies. + * Source/NSException.m: Re-instate correct behavior and make the + comment about it more emphatic. + 2010-02-08 Jonathan Gillaspie + * Source/NSException.m - * Removed redundant call to _NSFoundationUncaughtExceptionHandler and added else blocks - to allow a set uncaught exception handler to NOT exit if capable of recovering. + * Removed redundant call to _NSFoundationUncaughtExceptionHandler + and added else blocks to allow a set uncaught exception handler + to NOT exit if capable of recovering. 2010-02-08 Richard Frith-Macdonald diff --git a/Headers/Foundation/NSAttributedString.h b/Headers/Foundation/NSAttributedString.h index fc59405ac..68925d3f7 100644 --- a/Headers/Foundation/NSAttributedString.h +++ b/Headers/Foundation/NSAttributedString.h @@ -72,6 +72,11 @@ extern "C" { //Retrieving character information - (NSUInteger) length; +/** Returns the string content of the receiver.
+ * NB. this is actually a proxy to the internal content (which may change) + * so if you need an immutable instance yu should copy the returned value, + * not jhust retain it. + */ - (NSString*) string; //Primitive method! //Retrieving attribute information diff --git a/Source/GSAttributedString.m b/Source/GSAttributedString.m index a2a6befcf..c2d88d875 100644 --- a/Source/GSAttributedString.m +++ b/Source/GSAttributedString.m @@ -52,7 +52,9 @@ #import "Foundation/NSRange.h" #import "Foundation/NSDebug.h" #import "Foundation/NSArray.h" +#import "Foundation/NSInvocation.h" #import "Foundation/NSLock.h" +#import "Foundation/NSProxy.h" #import "Foundation/NSThread.h" #import "Foundation/NSNotification.h" #import "Foundation/NSZone.h" @@ -61,6 +63,103 @@ static NSDictionary *blank; +@interface GSAttributedStringProxy : NSProxy +{ + NSString *string; +} +- (id) _initWithString: (NSString*)s; +@end + +@implementation GSAttributedStringProxy + +static Class NSObjectClass = nil; +static Class NSStringClass = nil; + ++ (void) initialize +{ + NSObjectClass = [NSObject class]; + NSStringClass = [NSString class]; +} + +- (Class) class +{ + return NSStringClass; +} + +- (void) dealloc +{ + [string release]; + [super dealloc]; +} + +- (void) forwardInvocation: (NSInvocation*)anInvocation +{ + SEL aSel = [anInvocation selector]; + + if (YES == [NSStringClass instancesRespondToSelector: aSel]) + { + [anInvocation invokeWithTarget: string]; + } + else + { + [NSException raise: NSGenericException + format: @"NSString(instance) does not recognize %s", + aSel ? GSNameFromSelector(aSel) : "(null)"]; + } +} + +- (NSUInteger) hash +{ + return [string hash]; +} + +- (id) _initWithString: (NSString*)s +{ + string = [s retain]; + return self; +} + +- (BOOL) isEqual: (id)other +{ + return [string isEqual: other]; +} + +- (BOOL) isMemberOfClass: (Class)c +{ + return (c == NSStringClass) ? YES : NO; +} + +- (BOOL) isKindOfClass: (Class)c +{ + return (c == NSStringClass || c == NSObjectClass) ? YES : NO; +} + +- (NSMethodSignature*) methodSignatureForSelector: (SEL)aSelector +{ + NSMethodSignature *sig; + + if (YES == [NSStringClass instancesRespondToSelector: aSelector]) + { + sig = [string methodSignatureForSelector: aSelector]; + } + else + { + sig = [super methodSignatureForSelector: aSelector]; + } + return sig; +} + +- (BOOL) respondsToSelector: (SEL)aSelector +{ + if (YES == [NSStringClass instancesRespondToSelector: aSelector]) + { + return YES; + } + return [super respondsToSelector: aSelector]; +} + +@end + @interface GSAttributedString : NSAttributedString { NSString *_textChars; @@ -79,6 +178,7 @@ static NSDictionary *blank; { NSMutableString *_textChars; NSMutableArray *_infoArray; + NSString *_proxy; } - (id) initWithString: (NSString*)aString @@ -591,7 +691,14 @@ SANITY(); - (NSString*) string { - return AUTORELEASE([_textChars copy]); + /* NB. This method is SUPPOSED to return a proxy to the mutable string! + * This is a performance feature documented ifor OSX. + */ + if (_proxy == nil) + { + _proxy = [[GSAttributedStringProxy alloc] _initWithString: _textChars]; + } + return _proxy; } - (NSDictionary*) attributesAtIndex: (unsigned)index @@ -881,6 +988,7 @@ SANITY(); - (void) dealloc { + [_proxy release]; RELEASE(_textChars); RELEASE(_infoArray); [super dealloc]; diff --git a/Source/GSString.m b/Source/GSString.m index d3efc52bb..5d4e5d4c5 100644 --- a/Source/GSString.m +++ b/Source/GSString.m @@ -831,11 +831,11 @@ fixBOM(unsigned char **bytes, NSUInteger*length, BOOL *owned, if (string == nil) [NSException raise: NSInvalidArgumentException format: @"-initWithString: given nil string"]; - c = GSObjCClass(string); - if (GSObjCIsKindOf(c, NSStringClass) == NO) + if (NO == [string isKindOfClass: NSStringClass]) // may be proxy [NSException raise: NSInvalidArgumentException format: @"-initWithString: given non-string object"]; + c = GSObjCClass(string); length = [string length]; if (GSObjCIsKindOf(c, GSCStringClass) == YES || c == NSConstantStringClass || (GSObjCIsKindOf(c, GSMutableStringClass) == YES @@ -2144,7 +2144,7 @@ isEqual_c(GSStr self, id anObject) } return NO; } - else if (GSObjCIsKindOf(c, NSStringClass)) + else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy { return (*equalImp)((id)self, equalSel, anObject); } @@ -2211,7 +2211,7 @@ isEqual_u(GSStr self, id anObject) } return NO; } - else if (GSObjCIsKindOf(c, NSStringClass)) + else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy { return (*equalImp)((id)self, equalSel, anObject); } @@ -4767,7 +4767,7 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException); } return NO; } - else if (GSObjCIsKindOf(c, NSStringClass)) + else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy { return (*equalImp)(self, equalSel, anObject); } @@ -4817,7 +4817,7 @@ NSAssert(_flags.owned == 1 && _zone != 0, NSInternalInconsistencyException); } return NO; } - else if (GSObjCIsKindOf(c, NSStringClass)) + else if (YES == [anObject isKindOfClass: NSStringClass]) // may be proxy { return (*equalImp)(self, equalSel, anObject); } diff --git a/Source/NSAttributedString.m b/Source/NSAttributedString.m index 275349f2b..b31aff690 100644 --- a/Source/NSAttributedString.m +++ b/Source/NSAttributedString.m @@ -157,7 +157,9 @@ static Class GSMutableAttributedStringClass; [aCoder encodeObject: [self string] forKey: @"NSString"]; if ([self length] > 0) { - NSDictionary* attrs = [self attributesAtIndex: 0 effectiveRange: NULL]; + NSDictionary *attrs; + + attrs = [self attributesAtIndex: 0 effectiveRange: NULL]; [aCoder encodeObject: attrs forKey: @"NSAttributes"]; } @@ -523,7 +525,7 @@ static Class GSMutableAttributedStringClass; return NO; length = [otherString length]; - if (length<=0) + if (length == 0) return YES; ownDictionary = [self attributesAtIndex: 0 diff --git a/Source/NSException.m b/Source/NSException.m index c5bae9647..d08cca96f 100644 --- a/Source/NSException.m +++ b/Source/NSException.m @@ -774,9 +774,7 @@ callUncaughtHandler(id value) { (*_NSUncaughtExceptionHandler)(value); } - else { - _NSFoundationUncaughtExceptionHandler(value); - } + _NSFoundationUncaughtExceptionHandler(value); } @implementation NSException @@ -924,19 +922,20 @@ callUncaughtHandler(id value) */ callUncaughtHandler(self); - /* - * The uncaught exception handler which is set has not - * exited, so we call the builtin handler, (undocumented - * behavior of MacOS-X). - * The standard handler is guaranteed to exit/abort. + /* The uncaught exception handler which is set has not exited, + * so we MUST call the builtin handler, (normal behavior of MacOS-X). + * The standard handler is guaranteed to exit/abort, which is the + * required behavioru for OSX compatibility. + * NB Cocoa's Exception Handling framework bypasses this behavior + * somehow ... if anyone contributes an implementation we could + * integrate it here. */ - //_NSFoundationUncaughtExceptionHandler(self); + _NSFoundationUncaughtExceptionHandler(self); } - else { - thread->_exception_handler = handler->next; - handler->exception = self; - longjmp(handler->jumpState, 1); - } + + thread->_exception_handler = handler->next; + handler->exception = self; + longjmp(handler->jumpState, 1); #endif }