Creating delegates on the spot with blocks

后端 未结 3 1097
无人及你
无人及你 2020-11-29 10:49

I love blocks and it makes me sad when I can\'t use them. In particular, this happens mostly every time I use delegates (e.g.: with UIKit classes, mostly pre-block functiona

3条回答
  •  一生所求
    2020-11-29 11:27

    Edit: This is what I've come up after having understood your requirement. This is just a quick hack, an idea to get you started, it's not properly implemented, nor is it tested. It is supposed to work for delegate methods that take the sender as their only argument. It works It is supposed to work with normal and struct-returning delegate methods.

    typedef void *(^UBDCallback)(id);
    typedef void(^UBDCallbackStret)(void *, id);
    
    void *UBDDelegateMethod(UniversalBlockDelegate *self, SEL _cmd, id sender)
    {   
        UBDCallback cb = [self blockForSelector:_cmd];
        return cb(sender);
    }
    
    void UBDelegateMethodStret(void *retadrr, UniversalBlockDelegate *self, SEL _cmd, id sender)
    {
        UBDCallbackStret cb = [self blockForSelector:_cmd];
        cb(retaddr, sender);
    }
    
    @interface UniversalBlockDelegate: NSObject
    
    - (BOOL)addDelegateSelector:(SEL)sel isStret:(BOOL)stret methodSignature:(const char *)mSig block:(id)block;
    
    @end
    
    @implementation UniversalBlockDelegate {
        SEL selectors[128];
        id blocks[128];
        int count;
    }
    
    - (id)blockForSelector:(SEL)sel
    {
        int idx = -1;
        for (int i = 0; i < count; i++) {
            if (selectors[i] == sel) {
                return blocks[i];
            }
        }
    
        return nil; 
    }
    
    - (void)dealloc
    {
        for (int i = 0; i < count; i++) {
            [blocks[i] release];
        }
        [super dealloc];
    }
    
    - (BOOL)addDelegateSelector:(SEL)sel isStret:(BOOL)stret methodSignature:(const char *)mSig block:(id)block
    {
        if (count >= 128) return NO;
    
        selectors[count] = sel;
        blocks[count++] = [block copy];
    
        class_addMethod(self.class, sel, (IMP)(stret ? UBDDelegateMethodStret : UBDDelegateMethod), mSig);
    
        return YES;
    }
    
    @end
    

    Usage:

    UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
    UniversalBlockDelegate *d = [[UniversalBlockDelegate alloc] init];
    webView.delegate = d;
    [d addDelegateSelector:@selector(webViewDidFinishLoading:) isStret:NO methodSignature:"v@:@" block:^(id webView) {
        NSLog(@"Web View '%@' finished loading!", webView);
    }];
    [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]]];
    

提交回复
热议问题