2012-05-04 76 views
6

有一個簡單的一次性任務需要一個進度條。 OpenSSL的有一個有用的 回調哪一個可以使用的是:但是我想沒有太多費周折從的ObjectiveC稱之爲ObjC塊和openssl C回調

rsa=RSA_generate_key(bits,RSA_F4,progressCallback,NULL); 

static void callback(int p, int n, void *arg) { 
    .. stuff 

MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES]; 
    hud.mode = MBProgressHUDModeAnnularDeterminate; 
    hud.labelText = @"Generating CSR"; 

    [self genReq:^(int p,int n,void *arg) { 
      hud.progress = --heuristic to guess where we are -- 
    } completionCallback:^{ 
      [MBProgressHUD hideHUDForView:self.view animated:YES]; 
    }]; 

隨着Genrec :作爲objC方法:

-(void)genReq:(void (^)(int,int,void *arg))progressCallback 
     completionCallback:(void (^)())completionCallback 
{ 
    ..... 
    rsa=RSA_generate_key(bits,RSA_F4,progressCallback,NULL); 
    assert(EVP_PKEY_assign_RSA(pkey,rsa)); 
    rsa=NULL; 
    .... 

    completionCallback(); 
} 

現在completionCallback();出色地和預期地工作。但我得到一個編譯器警告/錯誤,我不能平息時進度回調:

Passing 'void (^__strong)(int, int, void *)' to parameter of incompatible type 'void (*)(int, int, void *)' 

所以很好奇 - 什麼是適當的方式做到這一點?

謝謝,

Dw。

回答

7

所有的代碼只是輸入到這個答案,使用前仔細測試!

函數指針和塊不是一回事;前者只是對代碼的引用,後者是包含代碼和環境的封閉;它們不是可以互換的。

你當然可以在Objective-C中使用函數指針,所以這是你的第一選擇。

如果您想使用塊,那麼你需要找到一種方式來包裝一個塊,並把它作爲一個函數引用...

RSA_generate_key定義是:

RSA *RSA_generate_key(int num, 
         unsigned long e, 
         void (*callback)(int,int,void *), 
         void *cb_arg); 

第四參數可以是任何東西,並作爲回調的第三個參數傳遞;這表明,我們可以用一個指針一路傳遞一個C函數調用它:

typedef void (^BlockCallback)(int,int); 

static void callback(int p, int n, void *anon) 
{ 
    BlockCallback theBlock = (BlockCallback)anon; // cast the void * back to a block 
    theBlock(p, n);        // and call the block 
} 

- (void) genReq:(BlockCallback)progressCallback 
     completionCallback:(void (^)())completionCallback 
{ 
    ..... 
    // pass the C wrapper as the function pointer and the block as the callback argument 
    rsa = RSA_generate_key(bits, RSA_F4, callback, (void *)progressCallback); 
    assert(EVP_PKEY_assign_RSA(pkey,rsa)); 
    rsa = NULL; 
    .... 

    completionCallback(); 
} 

以及調用:

[self genReq:^(int p, int n) 
      { 
       hud.progress = --heuristic to guess where we are -- 
      } 
     completionCallback:^{ 
          [MBProgressHUD hideHUDForView:self.view animated:YES]; 
          } 
]; 

無論您需要任何橋樑類型轉換(用於ARC)是作爲練習留下!

+0

最可愛!而__bridge是ARC所需要的。慚愧,需要有回調()之間 - 即無法通過progressCallback作爲(void(*)(int,int,void *))從它的void(^ __強)(int,int,void * )直接。 –

+0

@ Dirk-WillemvanGulik - 支持塊自動傳遞的唯一合理方法,即閉包(代碼指針+環境)作爲函數指針(只是一個代碼指針)可以動態生成代碼存根;並且具有各種缺點。 C中的通用模式是指定一個帶有額外值的函數指針,通常是'void *'類型,可用於傳遞用戶定義的環境,從而手動構造閉包 - openssl遵循該模式,解決方案上面只是用它。 – CRD

+0

清除。再次感謝!)。已經挖掘到NSStackBlock,並使總體感覺。 –