设计模式帮助:独特对象池

rjs*_*ing 1 design-patterns objective-c

我正在寻找一种设计模式来管理一个对象池.线程可以请求一个对象,在我的例子中是一个表示远程主机的对象.

如果主机对象不存在,则创建它,添加到池中并返回引用.

如果另一个线程或对象请求相同的(远程主机)对象,它也会被赋予引用.如果请求了不同的远程主机,则会创建它并将其添加到对象的"池"中.

一旦任何线程或对象不再需要主机对象,就会从池中自行删除它.

  1. 是否有这种模式,它的名称是什么?
  2. 我将在Objective-C中实现这一点,任何特定的帮助都会很有用.

Jim*_*vey 5

使用NSMapTable(例如在iPhone上不可用)的替代方法是使用CoreFoundation等效项.那些可以包含常规的非保留指针.但是,您仍然需要从该列表中删除内容,但这可以在对象的-dealloc方法中轻松完成.

一种可能性是使用CFSet.这将要求您的对象全部响应-isEqual:-hash正确响应,以便该集合可以确定对象是否已准确存在.

例如(请注意,我没有编译它,但它应该至少90%正确):

static id __uniqueObjects = nil;    // GC uses NSHashTable, non-GC uses NSSet (inited using CFSet APIs)

@interface MyHost : NSObject
{
    NSURL * _hostURL;
}

@property (nonatomic, readonly) NSURL * hostURL;

+ (MyHost *) uniqueHost: (MyHost *) aHost;
+ (void) removeUniqueHost: (MyHost *) aHost;     // only used in non-GC environment

- (id) initWithURL: (NSURL *) hostURL;

@end

@implementation MyHost

- (id) initWithURL: (NSURL *) hostURL
{
    self = [super init];
    if ( self == nil )
        return ( nil );

    // use copy, because NSURL implements NSCopying protocol
    _hostURL = [hostURL copy];

    // if there's a version around already, release this instance
    MyHost * result = [[self class] uniqueHost: self];
    if ( result != self )
    {
        // set _hostURL to nil so we don't inadvertently remove anything from uniqueing table in -dealloc
        [_hostURL release];
        _hostURL = nil;
        [self release];
    }

    // return either self or a pre-existing unique instance
    return ( result );
}

- (void) dealloc
{
    // non-GC objects need to explicitly remove themselves from the uniqueing table
    [[self class] removeUniqueHost: self];
    [_hostURL release];
    [super dealloc];
}

// no need for -finalize -- under GC we use NSHashTable with weak references

- (NSUInteger) hash
{
    return ( [_hostURL hash] );
}

- (BOOL) isEqual: (MyHost *) other
{
    if ( other == self )
        return ( YES );

    return ( [_hostURL isEqual: other->_hostURL] );
}

+ (MyHost *) uniqueHost: (MyHost *) aHost
{
    if ( __uniqueObjects == nil )
    {
        // use low-level routine to check, because iPhone has no NSGarbageCollector class
        // we use NSHashTable or NSMutableSet, because they both respond to the same messages (NSHashTable is modeled on NSMutableSet)
        if ( objc_collectingEnabled() )
        {
            // hash table has zeroing weak memory, object equality (uses -isEqual:), and does NOT copy objects, just retains them
            __uniqueObjects = [[NSHashTable hashTableWithWeakObjects] retain];
        }
        else
        {
            CFSetCallBacks cb = {
                0,                  // version
                NULL,               // retain (non-retaining references)
                NULL,               // release (non-retaining references)
                CFCopyDescription,  // CF (plain C function) equivalent for -description
                CFEqual,            // CF (plain C function) equivalent for -isEqual:
                CFHash              // CF (plain C function) equivalent for -hash
            }
            __uniqueObjects = (NSMutableSet *) CFSetCreateMutable( kCFAllocatorDefault, 0, &cb );
        }
    }

    MyHost * result = nil;
    @synchronized(__uniqueObjects)
    {
        // treat both like an NSMutableSet & we're golden
        // we use the -member: function to get an existing matching object from the collection
        result = [[__uniqueObjects member: aHost] retain];
        if ( result == nil )
        {
            // store & return the passed-in host object
            [__uniqueObjects addObject: aHost];
            result = aHost;
        }
    }

    return ( result );
}

+ (void) removeUniqueHost: (MyHost *) aHost
{
    if ( __uniqueObjects == nil )
        return;     // shouldn't ever happen, but it's a good idea to check at least

    @synchronized(__uniqueObjects)
    {
        [__uniqueObjects removeObject: aHost];
    }
}

@end
Run Code Online (Sandbox Code Playgroud)

希望我已经足够在这里回答您对此设计模式可能有的任何问题/想法.