mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-29 16:01:38 +00:00
Cleanups in preparation for experimental changes to retain/relase over DO.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@17949 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
bbb3b1786b
commit
9ecdf6cc0b
4 changed files with 159 additions and 201 deletions
19
ChangeLog
19
ChangeLog
|
@ -1,3 +1,22 @@
|
|||
Tue Oct 21 18:00:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Source/NSDistantObject.m: Retain local objects on creation,
|
||||
and release on deallocation ... don't depend on the connection
|
||||
to do it.
|
||||
* Source/NSConnection.m: Restructured handling of proxies ...
|
||||
remove global tables of local object references and just look in all
|
||||
connections and cache when a local object cannot be found in the
|
||||
current connection.
|
||||
Don't retain local objects ... depend on the NSDistantObject class
|
||||
to do that.
|
||||
Don't keep counters of the number of connections in which a local
|
||||
object reference is used ... it's not needed if we don't need to
|
||||
track whether to release the local object or not.
|
||||
Shorten timeout for deferred deallocation of local object references
|
||||
(temporary measure).
|
||||
* Headers/Foundation/NSDistantObject.h: new ivar for future use
|
||||
keeping track of number of times an object is vended.
|
||||
|
||||
Tue Oct 21 15:25:00 2003 Richard Frith-Macdonald <rfm@gnu.org>
|
||||
|
||||
* Testing/nsconnection_client.m: Add -r option.
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
id _object;
|
||||
unsigned _handle;
|
||||
Protocol *_protocol;
|
||||
unsigned _counter;
|
||||
}
|
||||
|
||||
+ (NSDistantObject*) proxyWithLocal: (id)anObject
|
||||
|
|
|
@ -104,7 +104,6 @@ static id dummyObject;
|
|||
static Class connectionClass;
|
||||
static Class dateClass;
|
||||
static Class distantObjectClass;
|
||||
static Class localCounterClass;
|
||||
static Class sendCoderClass;
|
||||
static Class recvCoderClass;
|
||||
static Class runLoopClass;
|
||||
|
@ -139,66 +138,26 @@ stringFromMsgType(int type)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* GSLocalCounter is a trivial class to keep track of how
|
||||
* many different connections a particular local object is vended
|
||||
* over. This is required so that we know when to remove an object
|
||||
* from the global list when it is removed from the list of objects
|
||||
* vended on a particular connection.
|
||||
*/
|
||||
@interface GSLocalCounter : NSObject
|
||||
{
|
||||
@public
|
||||
unsigned ref;
|
||||
unsigned target;
|
||||
id object;
|
||||
}
|
||||
+ (id) newWithObject: (id)ob;
|
||||
@end
|
||||
|
||||
@implementation GSLocalCounter
|
||||
|
||||
static unsigned local_object_counter = 0;
|
||||
|
||||
+ (id) newWithObject: (id)obj
|
||||
{
|
||||
GSLocalCounter *counter;
|
||||
|
||||
counter = (GSLocalCounter*)NSAllocateObject(self, 0, NSDefaultMallocZone());
|
||||
counter->ref = 1;
|
||||
counter->object = RETAIN(obj);
|
||||
counter->target = ++local_object_counter;
|
||||
return counter;
|
||||
}
|
||||
- (void) dealloc
|
||||
{
|
||||
RELEASE(object);
|
||||
NSDeallocateObject(self);
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* CachedLocalObject is a trivial class to keep track of how
|
||||
* many different connections a particular local object is vended
|
||||
* over. This is required so that we know when to remove an object
|
||||
* from the global list when it is removed from the list of objects
|
||||
* vended on a particular connection.
|
||||
* CachedLocalObject is a trivial class to keep track of local
|
||||
* proxies which have been removed from their connections and
|
||||
* need to persist a while in case another process needs them.
|
||||
*/
|
||||
@interface CachedLocalObject : NSObject
|
||||
{
|
||||
id obj;
|
||||
int time;
|
||||
NSDistantObject *obj;
|
||||
int time;
|
||||
}
|
||||
- (BOOL) countdown;
|
||||
- (id) obj;
|
||||
+ (id) newWithObject: (id)o time: (int)t;
|
||||
- (NSDistantObject*) obj;
|
||||
+ (id) newWithObject: (NSDistantObject*)o time: (int)t;
|
||||
@end
|
||||
|
||||
@implementation CachedLocalObject
|
||||
|
||||
+ (id) newWithObject: (id)o time: (int)t
|
||||
+ (id) newWithObject: (NSDistantObject*)o time: (int)t
|
||||
{
|
||||
CachedLocalObject *item;
|
||||
|
||||
|
@ -221,7 +180,7 @@ static unsigned local_object_counter = 0;
|
|||
return NO;
|
||||
}
|
||||
|
||||
- (id) obj
|
||||
- (NSDistantObject*) obj
|
||||
{
|
||||
return obj;
|
||||
}
|
||||
|
@ -338,10 +297,8 @@ setRootObjectForInPort(id anObj, NSPort *aPort)
|
|||
F_UNLOCK(root_object_map_gate);
|
||||
}
|
||||
|
||||
static NSMapTable *objectToCounter = NULL;
|
||||
static NSMapTable *targetToCounter = NULL;
|
||||
static NSMapTable *targetToCached = NULL;
|
||||
static NSLock *global_proxies_gate = nil;
|
||||
static NSLock *cached_proxies_gate = nil;
|
||||
|
||||
static BOOL multi_threaded = NO;
|
||||
|
||||
|
@ -370,9 +327,9 @@ static BOOL multi_threaded = NO;
|
|||
{
|
||||
connection_table_gate = [NSLock new];
|
||||
}
|
||||
if (global_proxies_gate == nil)
|
||||
if (cached_proxies_gate == nil)
|
||||
{
|
||||
global_proxies_gate = [NSLock new];
|
||||
cached_proxies_gate = [NSLock new];
|
||||
}
|
||||
if (root_object_map_gate == nil)
|
||||
{
|
||||
|
@ -579,7 +536,6 @@ static BOOL multi_threaded = NO;
|
|||
connectionClass = self;
|
||||
dateClass = [NSDate class];
|
||||
distantObjectClass = [NSDistantObject class];
|
||||
localCounterClass = [GSLocalCounter class];
|
||||
sendCoderClass = [NSPortCoder class];
|
||||
recvCoderClass = [NSPortCoder class];
|
||||
runLoopClass = [NSRunLoop class];
|
||||
|
@ -589,12 +545,6 @@ static BOOL multi_threaded = NO;
|
|||
connection_table =
|
||||
NSCreateHashTable(NSNonRetainedObjectHashCallBacks, 0);
|
||||
|
||||
objectToCounter =
|
||||
NSCreateMapTable(NSNonOwnedPointerMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
targetToCounter =
|
||||
NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
NSNonOwnedPointerMapValueCallBacks, 0);
|
||||
targetToCached =
|
||||
NSCreateMapTable(NSIntMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks, 0);
|
||||
|
@ -677,7 +627,7 @@ static BOOL multi_threaded = NO;
|
|||
NSArray *cached_locals;
|
||||
int i;
|
||||
|
||||
M_LOCK(global_proxies_gate);
|
||||
M_LOCK(cached_proxies_gate);
|
||||
cached_locals = NSAllMapTableValues(targetToCached);
|
||||
for (i = [cached_locals count]; i > 0; i--)
|
||||
{
|
||||
|
@ -685,8 +635,8 @@ static BOOL multi_threaded = NO;
|
|||
|
||||
if ([item countdown] == NO)
|
||||
{
|
||||
GSLocalCounter *counter = [item obj];
|
||||
NSMapRemove(targetToCached, (void*)counter->target);
|
||||
NSDistantObject *obj = [item obj];
|
||||
NSMapRemove(targetToCached, (void*)((ProxyStruct*)obj)->_handle);
|
||||
}
|
||||
}
|
||||
if ([cached_locals count] == 0)
|
||||
|
@ -694,7 +644,7 @@ static BOOL multi_threaded = NO;
|
|||
[t invalidate];
|
||||
timer = nil;
|
||||
}
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
M_UNLOCK(cached_proxies_gate);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1215,8 +1165,9 @@ static BOOL multi_threaded = NO;
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all the local proxies to objects that
|
||||
* are retained by the remote connection.
|
||||
* Returns an array of all the local objects that have proxies at the
|
||||
* remote end of the connection because they have been sent over the
|
||||
* connection and not yet released by the far end.
|
||||
*/
|
||||
- (NSArray*) localObjects
|
||||
{
|
||||
|
@ -1322,7 +1273,7 @@ static BOOL multi_threaded = NO;
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns an array of proxies to all the remote objects known to
|
||||
* Returns an array of proxies to all the remote objects known to
|
||||
* the NSConnection.
|
||||
*/
|
||||
- (NSArray *) remoteObjects
|
||||
|
@ -2495,6 +2446,10 @@ static void callEncoder (DOContext *ctxt)
|
|||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"forwarding exception for (0x%x) - %@",
|
||||
(gsaddr)self, localException);
|
||||
|
||||
/* Send the exception back to the client. */
|
||||
if (_isValid == YES)
|
||||
{
|
||||
|
@ -2672,7 +2627,7 @@ static void callEncoder (DOContext *ctxt)
|
|||
[rmc decodeValueOfObjCType: @encode(unsigned) at: &target];
|
||||
[self _doneInRmc: rmc];
|
||||
p = [self includesLocalTarget: target];
|
||||
o = ((ProxyStruct*)p)->_object;
|
||||
o = (p != nil) ? ((ProxyStruct*)p)->_object : nil;
|
||||
|
||||
/* xxx We should make sure that TARGET is a valid object. */
|
||||
/* Not actually a Proxy, but we avoid the warnings "id" would have made. */
|
||||
|
@ -3106,55 +3061,41 @@ static void callEncoder (DOContext *ctxt)
|
|||
/* Managing objects and proxies. */
|
||||
- (void) addLocalObject: (NSDistantObject*)anObj
|
||||
{
|
||||
static unsigned local_object_counter = 0;
|
||||
id object;
|
||||
unsigned target;
|
||||
GSLocalCounter *counter;
|
||||
GSIMapNode node;
|
||||
|
||||
M_LOCK(_proxiesGate);
|
||||
M_LOCK(global_proxies_gate);
|
||||
NSParameterAssert (_isValid);
|
||||
|
||||
object = ((ProxyStruct*)anObj)->_object;
|
||||
target = ((ProxyStruct*)anObj)->_handle;
|
||||
|
||||
/*
|
||||
* If there is no target allocated to the proxy, we add one.
|
||||
*/
|
||||
if (target == 0)
|
||||
{
|
||||
((ProxyStruct*)anObj)->_handle = target = ++local_object_counter;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the value in the _localObjects map, retaining it.
|
||||
*/
|
||||
object = ((ProxyStruct*)anObj)->_object;
|
||||
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)object);
|
||||
IF_NO_GC(RETAIN(anObj));
|
||||
if (node == 0)
|
||||
{
|
||||
GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
RELEASE(node->value.obj);
|
||||
node->value.obj = anObj;
|
||||
}
|
||||
NSAssert(node == 0, NSInternalInconsistencyException);
|
||||
node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
|
||||
NSAssert(node == 0, NSInternalInconsistencyException);
|
||||
|
||||
/*
|
||||
* Keep track of local objects accross all connections.
|
||||
*/
|
||||
counter = NSMapGet(objectToCounter, (void*)object);
|
||||
if (counter)
|
||||
{
|
||||
counter->ref++;
|
||||
target = counter->target;
|
||||
}
|
||||
else
|
||||
{
|
||||
counter = [localCounterClass newWithObject: object];
|
||||
target = counter->target;
|
||||
NSMapInsert(objectToCounter, (void*)object, counter);
|
||||
NSMapInsert(targetToCounter, (void*)target, counter);
|
||||
RELEASE(counter);
|
||||
}
|
||||
((ProxyStruct*)anObj)->_handle = target;
|
||||
RETAIN(anObj);
|
||||
GSIMapAddPair(_localObjects, (GSIMapKey)object, (GSIMapVal)anObj);
|
||||
GSIMapAddPair(_localTargets, (GSIMapKey)target, (GSIMapVal)anObj);
|
||||
|
||||
if (debug_connection > 2)
|
||||
NSLog(@"add local object (0x%x) target (0x%x) "
|
||||
@"to connection (0x%x) (ref %d)",
|
||||
(gsaddr)object, target, (gsaddr) self, counter->ref);
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
@"to connection (0x%x)", (gsaddr)object, target, (gsaddr) self);
|
||||
|
||||
M_UNLOCK(_proxiesGate);
|
||||
}
|
||||
|
||||
|
@ -3183,60 +3124,46 @@ static void callEncoder (DOContext *ctxt)
|
|||
{
|
||||
NSDistantObject *prox;
|
||||
unsigned target;
|
||||
GSLocalCounter *counter;
|
||||
unsigned val = 0;
|
||||
GSIMapNode node;
|
||||
|
||||
M_LOCK(global_proxies_gate);
|
||||
M_LOCK(_proxiesGate);
|
||||
|
||||
node = GSIMapNodeForKey(_localObjects, (GSIMapKey)anObj);
|
||||
if (node == 0)
|
||||
{
|
||||
M_UNLOCK(_proxiesGate);
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
[NSException raise: NSInternalInconsistencyException
|
||||
format: @"Attempt to remove non-existent local %@", anObj];
|
||||
}
|
||||
prox = node->value.obj;
|
||||
target = ((ProxyStruct*)prox)->_handle;
|
||||
|
||||
/*
|
||||
* If all references to a local proxy have gone - remove the
|
||||
* global reference as well.
|
||||
*/
|
||||
counter = NSMapGet(objectToCounter, (void*)anObj);
|
||||
if (counter)
|
||||
if (1)
|
||||
{
|
||||
counter->ref--;
|
||||
if ((val = counter->ref) == 0)
|
||||
id item;
|
||||
|
||||
M_LOCK(cached_proxies_gate);
|
||||
/*
|
||||
* If this proxy has been vended onwards by another process, we
|
||||
* need to keep a reference to the local object around for a
|
||||
* while in case that other process needs it.
|
||||
*/
|
||||
if (timer == nil)
|
||||
{
|
||||
if (1)
|
||||
{
|
||||
id item;
|
||||
/*
|
||||
* If this proxy has been vended onwards by another process, we
|
||||
* need to keep a reference to the local object around for a
|
||||
* while in case that other process needs it.
|
||||
*/
|
||||
if (timer == nil)
|
||||
{
|
||||
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
||||
target: connectionClass
|
||||
selector: @selector(_timeout:)
|
||||
userInfo: nil
|
||||
repeats: YES];
|
||||
}
|
||||
item = [CachedLocalObject newWithObject: counter time: 30];
|
||||
NSMapInsert(targetToCached, (void*)target, item);
|
||||
RELEASE(item);
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
|
||||
(gsaddr)anObj, target);
|
||||
}
|
||||
NSMapRemove(objectToCounter, (void*)anObj);
|
||||
NSMapRemove(targetToCounter, (void*)target);
|
||||
timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
||||
target: connectionClass
|
||||
selector: @selector(_timeout:)
|
||||
userInfo: nil
|
||||
repeats: YES];
|
||||
}
|
||||
item = [CachedLocalObject newWithObject: prox time: 5];
|
||||
NSMapInsert(targetToCached, (void*)target, item);
|
||||
M_UNLOCK(cached_proxies_gate);
|
||||
RELEASE(item);
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"placed local object (0x%x) target (0x%x) in cache",
|
||||
(gsaddr)anObj, target);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3256,7 +3183,6 @@ static void callEncoder (DOContext *ctxt)
|
|||
(gsaddr)anObj, target, (gsaddr)self, val);
|
||||
|
||||
M_UNLOCK(_proxiesGate);
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
}
|
||||
|
||||
- (void) _release_targets: (unsigned*)list count: (unsigned)number
|
||||
|
@ -3302,64 +3228,79 @@ static void callEncoder (DOContext *ctxt)
|
|||
NSDistantObject *proxy = nil;
|
||||
GSIMapNode node;
|
||||
|
||||
M_LOCK(global_proxies_gate);
|
||||
M_LOCK(_proxiesGate);
|
||||
node = GSIMapNodeForKey(_localTargets, (GSIMapKey)target);
|
||||
if (node != 0)
|
||||
{
|
||||
proxy = node->value.obj;
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
}
|
||||
else
|
||||
|
||||
/*
|
||||
* If not found in the current connection, try all other existing
|
||||
* connections.
|
||||
*/
|
||||
if (proxy == nil)
|
||||
{
|
||||
GSLocalCounter *counter;
|
||||
NSHashEnumerator enumerator;
|
||||
NSConnection *c;
|
||||
|
||||
counter = NSMapGet (targetToCounter, (void*)target);
|
||||
if (counter == nil)
|
||||
M_LOCK(connection_table_gate);
|
||||
enumerator = NSEnumerateHashTable(connection_table);
|
||||
while (proxy == nil
|
||||
&& (c = (NSConnection*)NSNextHashEnumeratorItem(&enumerator)) != nil)
|
||||
{
|
||||
CachedLocalObject *cached;
|
||||
|
||||
/*
|
||||
* If the target doesn't exist for any connection, but still
|
||||
* persists in the cache (ie it was recently released) then
|
||||
* we move it back from the cache to the main maps so we can
|
||||
* retain it on this connection.
|
||||
*/
|
||||
cached = NSMapGet (targetToCached, (void*)target);
|
||||
if (cached != nil)
|
||||
if (c != self && [c isValid] == YES)
|
||||
{
|
||||
unsigned t;
|
||||
id o;
|
||||
|
||||
counter = [cached obj];
|
||||
|
||||
t = counter->target;
|
||||
o = counter->object;
|
||||
|
||||
NSMapInsert(objectToCounter, (void*)o, counter);
|
||||
NSMapInsert(targetToCounter, (void*)t, counter);
|
||||
NSMapRemove(targetToCached, (void*)t);
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"target (0x%x) moved from cache", target);
|
||||
M_LOCK(c->_proxiesGate);
|
||||
node = GSIMapNodeForKey(c->_localTargets, (GSIMapKey)target);
|
||||
if (node != 0)
|
||||
{
|
||||
proxy = node->value.obj;
|
||||
/*
|
||||
* Found in another connection ... add to this one.
|
||||
*/
|
||||
[self addLocalObject: proxy];
|
||||
}
|
||||
M_UNLOCK(c->_proxiesGate);
|
||||
}
|
||||
}
|
||||
RETAIN(counter);
|
||||
M_UNLOCK(global_proxies_gate);
|
||||
if (counter == nil)
|
||||
NSEndHashTableEnumeration(&enumerator);
|
||||
M_UNLOCK(connection_table_gate);
|
||||
}
|
||||
|
||||
if (proxy == nil)
|
||||
{
|
||||
CachedLocalObject *cached;
|
||||
|
||||
/*
|
||||
* If the target doesn't exist for any connection, but still
|
||||
* persists in the cache (ie it was recently released) then
|
||||
* we move it back from the cache to the connection so we can
|
||||
* retain it on this connection.
|
||||
*/
|
||||
M_LOCK(cached_proxies_gate);
|
||||
cached = NSMapGet (targetToCached, (void*)target);
|
||||
if (cached != nil)
|
||||
{
|
||||
if(debug_connection > 3)
|
||||
NSLog(@"target (0x%x) not found anywhere", target);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert([counter isKindOfClass: [GSLocalCounter class]],
|
||||
@"Local counter is wrong kind of class.");
|
||||
proxy = [distantObjectClass proxyWithLocal: counter->object
|
||||
connection: self];
|
||||
proxy = [cached obj];
|
||||
/*
|
||||
* Found in cache ... add to this connection.
|
||||
*/
|
||||
ASSIGN(((ProxyStruct*)proxy)->_connection, self);
|
||||
[self addLocalObject: proxy];
|
||||
NSMapRemove(targetToCached, (void*)target);
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"retained object (0x%x) target (0x%x) on connection(0x%x)",
|
||||
counter->object, counter->target, self);
|
||||
RELEASE(counter);
|
||||
NSLog(@"target (0x%x) moved from cache", target);
|
||||
}
|
||||
M_UNLOCK(cached_proxies_gate);
|
||||
}
|
||||
|
||||
M_UNLOCK(_proxiesGate);
|
||||
|
||||
if (proxy == nil)
|
||||
{
|
||||
if (debug_connection > 3)
|
||||
NSLog(@"target (0x%x) not found anywhere", target);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
@ -3369,8 +3310,8 @@ static void callEncoder (DOContext *ctxt)
|
|||
NS_DURING
|
||||
{
|
||||
/*
|
||||
* Tell the remote app that it must retain the local object
|
||||
* for the target on this connection.
|
||||
* Tell the remote app that it must retain the local object
|
||||
* for the target on this connection.
|
||||
*/
|
||||
if (_receivePort && _isValid)
|
||||
{
|
||||
|
@ -3442,7 +3383,7 @@ static void callEncoder (DOContext *ctxt)
|
|||
return p;
|
||||
}
|
||||
|
||||
- (void) addProxy: (NSDistantObject*) aProxy
|
||||
- (void) addProxy: (NSDistantObject*)aProxy
|
||||
{
|
||||
unsigned target;
|
||||
GSIMapNode node;
|
||||
|
|
|
@ -726,15 +726,10 @@ enum
|
|||
return new_proxy;
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't need to retain the object here - the connection
|
||||
* will retain the proxies local object if necessary (and release it
|
||||
* when all proxies referring to it have been released).
|
||||
*/
|
||||
_object = anObject;
|
||||
_object = RETAIN(anObject);
|
||||
|
||||
/*
|
||||
* We register this proxy with the connection using it.
|
||||
* We register this proxy with the connection using it.
|
||||
*/
|
||||
_connection = RETAIN(aConnection);
|
||||
[_connection addLocalObject: self];
|
||||
|
@ -831,7 +826,7 @@ enum
|
|||
return sig;
|
||||
}
|
||||
/*
|
||||
* Simlarly, when we fetch a method signature form the remote end,
|
||||
* Simlarly, when we fetch a method signature from the remote end,
|
||||
* we get a proxy, and when we build a local signature we need to
|
||||
* ask the proxy for its types ... and must avoid recursion again.
|
||||
*/
|
||||
|
@ -986,19 +981,21 @@ enum
|
|||
NSLog(@"retain count for connection (0x%x) is now %u\n",
|
||||
(gsaddr)_connection, [_connection retainCount]);
|
||||
/*
|
||||
* A proxy for local object does not retain it's target - the
|
||||
* NSConnection class does that for us - so we need not release it.
|
||||
* A proxy for local object retains its target - so we release it.
|
||||
* For a local object the connection also retains this proxy, so we
|
||||
* can't be deallocated unless we are already removed from the
|
||||
* connection.
|
||||
* connection, and there is no need to remove self from connection.
|
||||
*
|
||||
* A proxy retains it's connection so that the connection will
|
||||
* continue to exist as long as there is a something to use it.
|
||||
* A proxy has a nil local object, and retains it's connection so
|
||||
* that the connection will continue to exist as long as there is
|
||||
* a something to use it.
|
||||
* So we release our reference to the connection here just as soon
|
||||
* as we have removed ourself from the connection.
|
||||
*/
|
||||
if (_object == nil)
|
||||
[_connection removeProxy: self];
|
||||
else
|
||||
DESTROY(_object);
|
||||
RELEASE(_connection);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue