I'm playing with Objective-C Distributed Objects and I'm having some problems understanding how memory management works under the system. The example given below illustrates my problem:
Protocol.h
#import <Foundation/Foundation.h>
@protocol DOServer
- (byref id)createTarget;
@end
Server.m
#import <Foundation/Foundation.h>
#import "Protocol.h"
@interface DOTarget : NSObject
@end
@interface DOServer : NSObject < DOServer >
@end
@implementation DOTarget
- (id)init
{
if ((self = [super init]))
{
NSLog(@"Target created");
}
return self;
}
- (void)dealloc
{
NSLog(@"Target destroyed");
[super dealloc];
}
@end
@implementation DOServer
- (byref id)createTarget
{
return [[[DOTarget alloc] init] autorelease];
}
@end
int main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
DOServer *server = [[DOServer alloc] init];
NSConnection *connection = [[NSConnection new] autorelease];
[connection setRootObject:server];
if ([connection registerName:@"test-server"] == NO)
{
NSLog(@"Failed to vend server object");
}
else
{
while (YES)
{
NSAutoreleasePool *innerPool = [[NSAutoreleasePool alloc] init];
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow:0.1f]];
[innerPool drain];
}
}
[pool drain];
return 0;
}
Client.m
#import <Foundation/Foundation.h>
#import "Protocol.h"
int main()
{
unsigned i = 0;
for (; i < 3; i ++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id server = [NSConnection rootProxyForConnectionWithRegisteredName:@"test-server"
host:nil];
[server setProtocolForProxy:@protocol(DOServer)];
NSLog(@"Created target: %@", [server createTarget]);
[[NSRunLoop currentRunLoop] runUntilDate:
[NSDate dateWithTimeIntervalSinceNow:1.0]];
[pool drain];
}
return 0;
}
The issue is that any remote objects created by the root proxy are not released when their proxy counterparts in the client go out of scope. According to the documentation:
When an object’s remote proxy is deallocated, a message is sent back to the receiver to notify it that the local object is no longer shared over the connection.
I would therefore expect that as each DOTarget
goes out of scope (each time around the loop) it's remote counterpart would be dellocated, since there is no other reference to it being held on the remote side of the connection.
In reality this does not happen: the temporary objects are only deallocate when the client application quits, or more accurately, when the connection is invalidated. I can force the temporary objects on the remote side to be deallocated by explicitly invalidating the NSConnection object I'm using each time around the loop and creating a new one but somehow this just feels wrong.
Is this the correct behaviour from DO? Should all temporary objects live as long as the connection that created them? Are connections therefore to be treated as temporary objects which should be opened and closed with each series of requests against the server?
Any insights would be appreciated.