How to declare a method that takes a block as a callback - objective-c

I have a method that I'd like to call like so:
void (^someblock)()=^{
NSLog(#"I want to know");
};
[Item getCacheAndCallback:self.menuItemID andCallback:someblock];
How would I declare this in my header file? I have tried
+(void)getCacheAndCallback:(int)menuItemID andCallback:(^());
but says "Expected a type". I thought this was supposed to go to void for type.

+(void)getCacheAndCallback:(int)menuItemID andCallback:(void(^)(void))completionBlock;

Putting block types directly into method signatures can get messy as you've found. I would suggest you use a typedef to make it cleaner:
typedef void(^VoidBlock)();
Now you can write your block declaration as:
VoidBlock someBlock = ^{ NSLog(#"I want to know"); };
and your method declaration as:
+ (void) getCacheAndCallback:(int)menuItemID andCallback:(VoidBlock)callBack;
Note: that typedef does not introduce a new type, just a shorthand. This means, for example, that you can declare a block using the full type (or even a different typedef with the same full type) and use it as VoidBlock.

Block syntax is weird. I keep this link handy to reference any time I happen to forget something: fuckingblocksyntax.com

Related

Why does Block use struct __Block_byref_object_0 instead of a single pointer to capture a variable decorated with "__block"

Here is my source code in file main.m
__block NSInteger blockInteger = 123;
static NSInteger staticInteger = 123;
void (^testBlock)(void) = ^() {
blockInteger++;
staticInteger++;
NSLog(#"%ld", blockInteger);
NSLog(#"%ld", staticInteger);
};
testBlock();
When I used clang command "clang -rewrite-objc main.m", I got this
struct __Block_byref_blockInteger_0 {
void *__isa;
__Block_byref_blockInteger_0 *__forwarding;
int __flags;
int __size;
NSInteger blockInteger;
};
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
NSInteger *staticInteger;
__Block_byref_blockInteger_0 *blockInteger; // by ref
...
};
I am wondering why block use __Block_byref_blockInteger_0 to capture blockInteger since it use a NSInteger pointer to capture a static variable . What does __Block_byref_blockInteger_0 exactly do? What are the advantages of this struct by comparing with a pointer?
The compiler is creating a number of structures to help the block refer to its "enclosed" values. (Remember that a block makes a copy of, or "encloses", all of the values that are outside the block, which is why blocks are also called "closures".)
So the first structure (__Block_byref_blockInteger_0) is creating an object to encapsulate the blockInteger automatic. This is because automatic variables disappear at the end of the function, but blocks must be able to refer to them long afterwards.
The second structure encapsulates all of the values (including __Block_byref_blockInteger_0) that are being "captured" by the block. This give the block a single reference to all of its enclosed values, copied when the block was created.
Now the NSInteger *staticInteger instance value is a bit of an odd duck, since the address of the global staticInteger can't change. But that's a pretty minor difference as it's still just a copy of an address; whether that address can change is immaterial.
I suspect it's because of name scope; a static declared inside a function has a symbol scope limited to that function. And if you look at the compiler output, you'll see that every block you declare creates an invisible static function to contain its code. Since that second static function wouldn't normally be able to reference a static declared within another function, making a copy of the static's address is the only way for the block function to access it.

Is there a way to reflectively call a function in Objective-C from a string?

Are there any Objective-C runtime functions that will allow me to get a function (or block) pointer from a string identifying the function? I need some way to dynamically find and invoke a function or static method based on some form of string identifying it.
Ideally this function should be able to exist in any dynamically loaded library.
Looking at Objective-C Runtime Reference, the best bet looks like class_getClassMethod, but there don't appear to be any function-related functions in this reference. Are there other raw C ways of getting a pointer to a function by name?
if you want to invoke some static objc method, you can make it as a class method of a class
#interface MyClas : NSObject
+ (int)doWork;
#end
and call the method by
[[MyClass class] performSelector:NSSelectorFromString(#"doWork")];
if you real want to work with C-style function pointer, you can check dlsym()
dlsym() returns the address of the code or data location specified by
the null-terminated character
string symbol. Which libraries and bundles are searched depends on the handle
parameter If dlsym() is called with the special handle RTLD_DEFAULT,
then all mach-o images in the process
(except those loaded with dlopen(xxx, RTLD_LOCAL)) are searched in the order they were loaded. This
can be a costly search and should be avoided.
so you can use it to find the function pointer base on asymbol name
not sure why you want to do this, sometimes use function table can do
typedef struct {
char *name,
void *fptr // function pointer
} FuncEntry;
FuncEntry table[] = {
{"method", method},
{"method2", method2},
}
// search the table and compare the name to locate function, you get the idea
If you know method signature you can create selector to it with NSSelectorFromString function, e.g.:
SEL selector = NSSelectorFromString(#"doWork");
[worker performSelector:selector];
You may be able to do what you want with libffi. But unless you are doing something like create your own scripting language or something like that where you need to do this sort of thing a lot. It is probable overkill
I've wondered the SAME thing.. and I guess, after having researched it a bit.. there is NOT a "standard C" way to do such a thing.. (gasp).. but to the rescue? Objective C blocks!
An anonymous function.. that can be OUTSIDE any #implementation, etc...
void doCFunction() { printf("You called me by Name!"); }
Then, in your objective-C method… you can somehow "get" the name, and "call" the function...
NSDictionary *functionDict = #{ #"aName" : ^{ doCFunction(); } };
NSString *theName = #"aName";
((void (^)()) functionDict[theName] )();
Result: You called me by Name!
Loves it! 👓 ⌘ 🐻

Convert a selector to its class_addMethod() encoding at compile time

I have the following Objective-C code in a testing harness for some crazy low-level code (don't ask):
/* This category is declared here but not defined anywhere.
* It lets me write
* id MyNewClass = objc_lookUpClass("MyNewClass");
* [MyNewClass class_method];
* without spurious compiler warnings.
*/
#interface NSObject (MyNewClass)
+(void) class_method;
+(void) class_method_taking_int: (int) f;
-(int) method_returning_int: (int) i;
#end
...
{
Class MyNewClass = objc_allocateClassPair([NSObject class], "MyNewClass", 0);
Class MyNewClass_meta = object_getClass(cls);
class_addMethod(MyNewClass_meta, #selector(class_method),
(IMP)..., "v#:");
class_addMethod(MyNewClass_meta, #selector(class_method_taking_int:),
(IMP)..., "v#:i");
class_addMethod(MyNewClass, #selector(method_returning_int:),
(IMP)..., "i#:i");
objc_registerClassPair(MyNewClass);
}
I'd like to be able to eliminate all those literal "v#:i" and so on. After all, those are supposed to be just the encodings of the method signatures as listed in the NSObject (MyNewClass) category. So I feel like I ought to be able to write something like
class_addMethod(MyNewClass_meta, #selector(class_method_taking_int:),
(IMP)..., #encode(__typeof__(+[NSObject class_method_taking_int:])));
Of course the syntax above is fantasy, but shouldn't there be something like this in Objective-C? And then I could hide the whole thing behind a simple macro and the code would be just beautiful.
Notice that I cannot use methodSignatureForSelector, because that assumes that I have an object that responds to the given selector, which I don't, because I haven't registered my class yet.
Also notice that the format of the string expected by class_addMethod isn't the same as the format of the string returned by #encode(foo), and in fact #encode(foo) can't encode function types at all — it just gives back "?" or "^?". So I guess I can't literally use #encode.
But is there anything I can do?

How do I pass (by value) a struct in Objective-C?

This one has been driving me mad! I have a struct:
typedef struct{
int a;
}myStruct;
Then I have:
myStruct tempStruct;
I am trying to pass the struct to a class method whose implementation is:
- (void) myFunc:(struct myStruct)oneOfMyStructs{};
I call the method like so:
[myClass myFunc:(struct myStruct)tempStruct];
The compiler complains about "Conversion to non-scalar type requested." All I want to do is pass a struct into a class method, but the syntax has me a bit confused. I'm new to Objective-C. Please let me know if you can see where I'm going wrong. I've not been able to pass by reference either, so if you could help me out with that, that would be great!
Thanks!
Since you have typedef-ed it to myStruct, you don't need to (indeed mustn't) include the struct keyword in the function signature or the call:
typedef struct tag_myStruct
{
int a;
}
myStruct;
- (void) myFunc:(myStruct) x {}
[myClass myFunc:tmpStruct];
should be sufficient. (Compare all those Cocoa functions that take things like NSRects.)

Functions in Objective-C

I am trying to write a function which returns a string created from two input strings;
but when I try the function declaration
NSString Do_Something(NSString str1, NSString str2)
{
}
the compiler gets sick. (Worked fine for a different function with int arguments.)
If I change the input arguments to pointers to strings, in also gets sick.
So how do I pass Objective-C objects into a function?
All Objective-C objects being passed to functions must be pointers. Rewriting it like this will fix your compiler error:
NSString *Do_Something(NSString *str1, NSString *str2) { }
Also, please keep in mind that this is a (C-style) function and not an instance method written on an Objective-C object. If you wanted this to actually be a method on an object it would probably look something like this:
NSString *doSomethingWithString1:(NSString *)str1 string2:(NSString *)str2 { }
I say "probably" because you can name it however you want.
Functions are perfectly fine in Objective-C (and in fact earn some of the language's benefits).
See my answer to C function always returns zero to Objective C, where someone was trying what you are and had a problem with the compiler assuming return type. The structure that I set up there is important when you are using functions, just like when you are using objects and methods. Be sure to get your headers right.
To be pedantic, you're using a function definition of:
NSString *DoSomething(NSString *str1, NSString *str2) {
// Drop the _ in the name for style reasons
}
And you should be declaring it in a .h file like so:
NSString *DoSomething(NSString *str1, NSString *str2);
Just like C.
that doesn't work for me. i've just declared in the .h:
NSString *myFunction(NSDecimal *value);
and i type in the .m:
NSString *myFunction(NSDecimal *value){
//code
}
but always i get an error saying expected '(' before '*' token
now is fixed. for some reason... sorry.