ObjC blocks & opens C callbacks

You have simple one-time tasks that require a progress bar. OpenSSL has a useful callback that you can use to do this:

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

from

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

However, I want to call it from ObjectiveC without much ado:

  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]; }]; 

With Genrec: as an objC method:

 -(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(); } 

Now completeCallback (); Works great and as expected. But I get a compiler warning / error that I cannot suppress for the progress callback:

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

So curious - which way to do it?

Thanks,

Dw.

+6
source share
1 answer

All code is simply entered into this answer, check carefully before use!

Function pointers and blocks are not the same thing; the first is just a link to the code, the last is a closure containing both the code and the environment; they are not trivially interchangeable.

Of course, you can use function pointers in Objective-C, so this is your first option.

If you want to use blocks, you need to find a way to wrap the block and pass it as a function reference ...

RSA_generate_key definition:

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

The fourth argument can be any and is passed as the third argument to the callback; this suggests that we could pass the block along with a pointer to a C function that calls it:

 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(); } 

And to call:

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

If you need any bridges (for ARC), it remains as an exercise!

+7
source

Source: https://habr.com/ru/post/914875/


All Articles