将块保留在字典中

vgr*_*vgr 14 nsdictionary grand-central-dispatch ios objective-c-blocks

我有自己的方法,以块作为参数.我想跟踪NSDictionary中的那个块.将块添加到字典的最佳方法是什么?

我尝试了这段代码但是在执行下面的行(setObject ...)后,字典仍然是空的.我认为这是因为该块不是NSObject类型.但是这样做的正确方法是什么?

- (void)startSomething:(NSURLRequest*)request block:(void (^)(NSURLResponse*, NSData*, NSError*))handler {

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];

    [pendingRequests setObject:handler forKey:connection];
}
Run Code Online (Sandbox Code Playgroud)

编辑:

没关系.我不知道我在想什么.3分:

  1. 块是objc对象
  2. 错字:setObject应该是setValue
  3. forKey是一个字符串,因此它应该是[连接描述]或类似的东西

无论如何我现在解决了我的问题:

- (void)startSomething:(NSURLRequest*)request block:(void (^)(NSURLResponse*, NSData*, NSError*))handler {

    NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
    [pendingRequests setValue:handler forKey:[connection description]];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {

        void (^handler)(NSURLResponse*, NSData*, NSError*);
        handler = [pendingRequests valueForKey:[connection description]];
        handler(nil, nil, nil);
    });
}
Run Code Online (Sandbox Code Playgroud)

bbu*_*bum 22

这仍然无法发挥作用,或者充其量只会巧合.

您需要在将其handler推入字典之前复制它.就像是:

void (^handlerCopy)(NSURLResponse*, NSData*, NSError*) = Block_copy(handler);
[dict setObject:handlerCopy forKey:@"foo"];
Block_release(handlerCopy); // dict will -retain/-release, this balances the copy.
Run Code Online (Sandbox Code Playgroud)

而且,是的,它应该是setObject:forKey:objectForKey:.


Joh*_*ool 12

如果您使用ARC,请使用-copy:

 void (^handlerCopy)(NSURLResponse*, NSData*, NSError*) = [handler copy];
 [dict setObject:handlerCopy forKey:@"foo"];
Run Code Online (Sandbox Code Playgroud)


new*_*cct 5

"错字:setObject应该是setValue"

不,你应该总是使用setObject:而不是setValue:.setValue:用于键值编码,巧合的工作类似于setObject:字典(即使这样,它不一样,例如当键是"@something"),setObject:而是将事物放入字典中的正确方法,并且正确地将所有类型作为键.(顺便说一下,我不确定你想用它connection作为一个键,因为它会复制它.)

真正的问题是,在将块存储在可能比块的原始范围更长的内容之前需要复制块(这是块的特殊问题而不是其他对象的问题),因为块(与其他对象不同)最初是在堆栈上,因此保留它不会阻止它被解除分配.把东西放在字典中通常会保留它,但在这种情况下这还不够.

[pendingRequests setObject:[[handler copy] autorelease] forKey:connection];
Run Code Online (Sandbox Code Playgroud)