diff --git a/ChangeLog b/ChangeLog index bcfb5b7cd..44b80372f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2005-09-17 Saso Kiselkov + + * Headers/Foundation/NSInvocation.h: + * Source/NSInvocation.m: + (-targetRetained, -retainArgumentsIncludingTarget:): + Added new methods which allow target to be not retained when arguments + are and to check whether it is retained or not (-retainsArguments code + moved in -retainArgumentsIncludingTarged and simplified by removing a + redundant nested branch statement). + * Source/NSUndoManager.m (-forwardInvocation:, + -registerUndoWithTarget:selector:object:): Fixed bug #14488 by relying + on previous new methods to retain undo invocation (taking in account + the fact arguments may have been released before it is called). + Patch committed by Quentin Mathe. + 2005-09-01 Adam Fedor * Source/NSSortDescriptor.m ([NSArray diff --git a/Headers/Foundation/NSInvocation.h b/Headers/Foundation/NSInvocation.h index dc26300c0..ff5f81ac1 100644 --- a/Headers/Foundation/NSInvocation.h +++ b/Headers/Foundation/NSInvocation.h @@ -42,6 +42,7 @@ void *_dummy; #endif BOOL _argsRetained; + BOOL _targetRetained; BOOL _validReturn; BOOL _sendToSuper; } @@ -71,6 +72,11 @@ - (BOOL) argumentsRetained; - (void) retainArguments; +#if OS_API_VERSION(GS_API_NONE,GS_API_NONE) && GS_API_VERSION(011201,GS_API_LATEST) +- (BOOL) targetRetained; +- (void) retainArgumentsIncludingTarget: (BOOL)retainTargetFlag; +#endif + /* * Dispatching an Invocation. */ diff --git a/Source/NSInvocation.m b/Source/NSInvocation.m index 82263289f..c20bf43ba 100644 --- a/Source/NSInvocation.m +++ b/Source/NSInvocation.m @@ -189,9 +189,13 @@ _arg_addr(NSInvocation *inv, int index) - (void) dealloc { + if (_targetRetained) + { + _targetRetained = NO; + RELEASE(_target); + } if (_argsRetained) { - RELEASE(_target); _argsRetained = NO; if (_cframe && _sig) { @@ -437,11 +441,14 @@ _arg_addr(NSInvocation *inv, int index) */ - (void) setTarget: (id)anObject { - if (_argsRetained) + if (_targetRetained) { ASSIGN(_target, anObject); } - _target = anObject; + else + { + _target = anObject; + } } /** @@ -463,55 +470,73 @@ _arg_addr(NSInvocation *inv, int index) /** * Instructs the invocation to retain its object arguments (including the - * target). The default is not to retain them. + * target). The default is not to retain them. */ - (void) retainArguments { - if (_argsRetained) - { - return; - } - else + [self retainArgumentsIncludingTarget: YES]; +} + +/** + * Returns YES if target has been retained yet, NO otherwise. + */ +- (BOOL) targetRetained +{ + return _targetRetained; +} + +/** + * Similar to -[NSInvocation retainArguments], but allows the sender to + * explicitly control whether the target is retained as well. Retaining + * the target is sometimes not desirable (such as in NSUndoManager), as + * retain loops could result. + */ +- (void) retainArgumentsIncludingTarget: (BOOL)retainTargetFlag +{ + if (_argsRetained == NO) { unsigned int i; _argsRetained = YES; - IF_NO_GC(RETAIN(_target)); if (_cframe == 0) { return; } for (i = 3; i <= _numArgs; i++) { - if (*_info[i].type == _C_ID || *_info[i].type == _C_CHARPTR) + if (*_info[i].type == _C_ID) { - if (*_info[i].type == _C_ID) - { - id old; + id old; - _get_arg(self, i-1, &old); - if (old != nil) - { - IF_NO_GC(RETAIN(old)); - } + _get_arg(self, i-1, &old); + if (old != nil) + { + IF_NO_GC(RETAIN(old)); } - else - { - char *str; + } + else if (*_info[i].type == _C_CHARPTR) + { + char *str; - _get_arg(self, i-1, &str); - if (str != 0) - { - char *tmp; + _get_arg(self, i-1, &str); + if (str != 0) + { + char *tmp; - tmp = NSZoneMalloc(NSDefaultMallocZone(), strlen(str)+1); - strcpy(tmp, str); - _set_arg(self, i-1, &tmp); - } + tmp = NSZoneMalloc(NSDefaultMallocZone(), strlen(str)+1); + strcpy(tmp, str); + _set_arg(self, i-1, &tmp); } } } - } + } + + if (retainTargetFlag && _targetRetained == NO) + { + _targetRetained = YES; + + IF_NO_GC(RETAIN(_target)); + } } /** diff --git a/Source/NSUndoManager.m b/Source/NSUndoManager.m index b1e898784..14cd86f88 100644 --- a/Source/NSUndoManager.m +++ b/Source/NSUndoManager.m @@ -425,6 +425,7 @@ format: @"forwardInvocation without beginUndoGrouping"]; } } + [anInvocation retainArgumentsIncludingTarget: NO]; [anInvocation setTarget: _nextTarget]; _nextTarget = nil; [_group addInvocation: anInvocation]; @@ -726,7 +727,7 @@ g = _group; sig = [target methodSignatureForSelector: aSelector]; inv = [NSInvocation invocationWithMethodSignature: sig]; - [inv retainArguments]; + [inv retainArgumentsIncludingTarget: NO]; [inv setTarget: target]; [inv setSelector: aSelector]; [inv setArgument: &anObject atIndex: 2];