Have a simple one-off tasks which needs a progress bar. OpenSSL has a useful callback which one can use for that:
rsa=RSA_generate_key(bits,RSA_F4,progressCallback,NULL);
with
static void callback(int p, int n, void *arg) {
.. stuff
However I want to call this from ObjectiveC without too 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 completionCallback(); works splendidly and as expected. But I get a compiler warning/error which I cannot quell for the progress callback:
Passing 'void (^__strong)(int, int, void *)' to parameter of incompatible type 'void (*)(int, int, void *)'
So am curious -- what is the appropriate way to do this ?
Thanks,
Dw.
Blocks are a language-level feature added to C, Objective-C and C++ which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects which means they can be added to collections like NSArray or NSDictionary.
^blockName: Always remember that the block name is preceded by the ^ symbol. The block name can be any string you like, just like you name any other variable or method. Remember that both the ^ and the block name are enclosed in parentheses ().
Closures in Swift Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.
The goal of the @property directive is to configure how an object can be exposed. If you intend to use a variable inside the class and do not need to expose it to outside classes, then you do not need to define a property for it. Properties are basically the accessor methods.
“id” is a data type of object identifiers in Objective-C, which can be use for an object of any type no matter what class does it have. “id” is the final supertype of all objects.
All code is just typed into this answer, test carefully before using!
Function pointers and blocks are not the same thing; the former is just a reference to code, the latter is a closure containing both code and an environment; they are not trivially interchangeable.
You can of course use function pointers in Objective-C, so that is your first option.
If you wish to use blocks then you need to find a way to wrap a block and pass it as a function reference...
The definition of RSA_generate_key
is:
RSA *RSA_generate_key(int num,
unsigned long e,
void (*callback)(int,int,void *),
void *cb_arg);
The fourth argument can be anything and is passed as the third argument to the callback; this suggests we could pass the block along with a pointer to a C function which 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 invoke:
[self genReq:^(int p, int n)
{
hud.progress = --heuristic to guess where we are --
}
completionCallback:^{
[MBProgressHUD hideHUDForView:self.view animated:YES];
}
];
Whether you need any bridge casts (for ARC) is left as an exercise!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With