保留代表直到使用它

时间:2012-01-10 21:02:52

标签: objective-c automatic-ref-counting objective-c-blocks

所以我正在编写看起来像这样的API:

    @implementation TheApi
    - (ObjectLoaderCallbackDelegate *)createLoaderDelegateForCallback:(ObjectLoaderCallback)callback
    {
        ObjectLoaderCallbackDelegate *loaderDelegate = [[ObjectLoaderCallbackDelegate alloc] init];
        loaderDelegate.didLoadObject = ^(id object) {
            callback(object);
        };
        return loaderDelegate;
    }

    - (void)loadString:(ObjectLoaderCallback)callback
    {
        ObjectLoaderCallbackDelegate *callbackDelegate = [self createLoaderDelegateForCallback:callback];
        ObjectLoader *loader = [[ObjectLoader alloc] init];
        [loader load:@"string" delegate:callbackDelegate];
    }

    - (void)loadNumber:(ObjectLoaderCallback)callback
    {
        ObjectLoaderCallbackDelegate *callbackDelegate = [self createLoaderDelegateForCallback:callback];
        ObjectLoader *loader = [[ObjectLoader alloc] init];
        [loader load:@"number" delegate:callbackDelegate];
    }
    @end

当我调用[loader load:delegate:]时,它不会保留对委托的强引用(这是有道理的)。但是因为加载器在调用委托之前执行异步操作,所以委托在被调用之前被释放,从而导致程序崩溃。这是我的解决方案(看起来有点脏):

    @interface TheApi : NSObject
    - (void)loadString:(ObjectLoaderCallback)callback;
    - (void)loadNumber:(ObjectLoaderCallback)callback;
    - (void)runCalls;
    @end

    @implementation TheApi
    {
        NSMutableDictionary *loaderDelegates;
        NSMutableSet *callbacksCompleted;
    }

    - (TheApi *) init
    {
        self = [super init];
        if (self != nil) {
            loaderDelegates = [[NSMutableDictionary alloc] init];
            callbacksCompleted = [[NSMutableSet alloc] init];
        }
        return self;
    }

    - (void)runCalls
    {
        [loader runLoop];
    }

    - (ObjectLoaderCallbackDelegate *)createLoaderDelegateForCallback:(ObjectLoaderCallback)callback
    {
        NSNumber *delegateRefKey = [NSNumber numberWithUnsignedInt:arc4random()];
        ObjectLoaderCallbackDelegate *loaderDelegate = [[ObjectLoaderCallbackDelegate alloc] init];
        loaderDelegate.didLoadObject = ^(id object) {
            callback(object);
            [callbacksCompleted addObject:delegateRefKey];
        };
        [loaderDelegates setObject:loaderDelegate forKey:delegateRefKey];
        return loaderDelegate;
    }

    - (void)removeCompletedDelegates
    {
        // So we can remove items from callbacksCompleted in the loop...
        NSMutableSet *callbacksCompletedIterSet = [callbacksCompleted copy];

        // Remove old delegates for calls already completed which are stored
        for (id key in callbacksCompletedIterSet) {
            [loaderDelegates removeObjectForKey:key];
            [callbacksCompleted removeObject:key];
        }
    }

    - (void)loadString:(ObjectLoaderCallback)callback
    {
        [self removeCompletedDelegates];
        ObjectLoaderCallbackDelegate *callbackDelegate = [self createLoaderDelegateForCallback:callback];
        ObjectLoader *loader = [[ObjectLoader alloc] init];
        [loader load:@"string" delegate:callbackDelegate];
    }

    - (void)loadNumber:(ObjectLoaderCallback)callback
    {
        [self removeCompletedDelegates];
        ObjectLoaderCallbackDelegate *callbackDelegate = [self createLoaderDelegateForCallback:callback];
        ObjectLoader *loader = [[ObjectLoader alloc] init];
        [loader load:@"number" delegate:callbackDelegate];
    }
    @end

所以在这里,我在实例级字典中保留对代理的引用,其中每个API方法调用的密钥都是唯一的。

所以我的问题是:有没有更好的方法来保持代理被释放,然后在加载器调用它们之后释放它们?

1 个答案:

答案 0 :(得分:0)

我最近问了similar question并了解了“相关对象”。这似乎可以解决您的问题。

@CRD在他的回答中提供了一个很好的解释 - 见https://stackoverflow.com/a/17351118/423565