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

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?

Related

Corrupted string when returning new string from objective-c to swift

I try to build a string from an enum in Objective-C:
+ (NSString *)getStringFromKey:(ITGenericNotification)key {
return [NSString stringWithFormat:#"notification%lu", (long)key];
}
This code worked really well for over a year
However when I try to call it from swift with:
let notificationKey = NSNotification.getStringFromKey(ITNotificationWithObject.DidChangedQuestion.hashValue)
I get a corrupted string :
What is happening ?
The value of ITGenericNotification seems to be correct,
ITGenericNotification is defined as typedef long ITGenericNotification; and is used as base type for an enum with typedef NS_ENUM(ITGenericNotification, ITNotificationWithObject)
And + (NSString *)getStringFromKey:(ITGenericNotification)key is implemented as a category to NSNotification
You probably want .rawValue, not .hashValue, to get the underlying
integer value of the enum.
(Also the debugger variables view is sometimes wrong. When in doubt,
add a println() or NSLog() to your code to verify the values of
your variables.)

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! 👓 ⌘ 🐻

Polymorphic methods in Objective C

In Java you can put in multiple constructors to a class that are called depending on the types and/or number of parameters that are used when an instance is constructed.
I assume that there is the equivalent in Objective C.
Can I have a polymorphic method?
I would like to build a method that acts slightly differently according to whether a string is passed or a double?
Does that sound bonkers or is it easy?
You're thinking of overloaded methods. Due to the way dynamic dispatch is implemented in Objective-C, it isn't currently possible to pass two unrelated types as arguments to the same (or same-named) method and have it understand.
In Objective-C, there are two related but distinct approaches to handling multiple kinds of input. Let's use your example of a string or a double as possible inputs. In Java, you might have:
void applyWidget(String s);
void applyWidget(double d);
And that's great, but not Objective-C. In Objective-C, you instead would use two different method names:
- (void)applyWidgetWithName: (NSString *)name;
- (void)applyWidgetWithValue: (double)value;
The same logic is in each method as in the Java version, but the distinct names let the compiler treat them as distinct methods (which they are, even in Java.) The code also becomes self-documenting: by reading it, you get an idea of what's happening even without comments. Alternatively, if you simply must have one method name, you change the parameter type to id and accept any object:
- (void)applyWidget: (id)widget;
Then pass either an NSString or an NSNumber wrapping your double. Then, in the implementation of the method, use Objective-C's introspection methods to determine how to proceed:
if ([widget isKindOfClass: [NSString class]]) {
...
} else if ([widget isKindOfClass: [NSNumber class]]) {
double d = [widget doubleValue];
...
}
This approach essentially tells callers "send anything--I'll handle it appropriately." It can be difficult to determine the behaviour of such a method without extensive documentation.
Absolutely easy:
- (id)initWithSomeObject:(id)object
{
if ([object isKindOfClass:[ClassOne class]) {
// do something
} else if ([object isKindOfClass:[ClassTwo class]) {
// do something else
} // etc.
return self;
}
yes, but objc does not have proper overloading.
so you see things like initWithDouble:, initWithBool: and so on. that's part of the reason it's a bit 'wordy' for some people's taste.
to use your example:
#interface MONClass
- (id)initWithString:(NSString *)pString;
- (id)initWithDouble:(double)pDouble;
...
but the following is an error:
- (id)initWith:(NSString *)pString;
- (id)initWith:(double)pDouble;
because the selector is the same -- the parameter/return types are omitted from the selector.
Basically Objective C does't have proper method overloading. It will support overriding only.
Suppose if you write functions like in same class,
(void) showMethod;
(void) showMethod:(int) aNumber;
This will support in Objective C.
Suppose if you write functions like,
(void) showMethod:(NSString*) aString;
(void) showMethod:(int) aNumber;
In this way the compiler gives Error because there conflicting parameter types in implementation of showMethod.

Retrieving data from singleton in a more clever way ?

I have some game data in my GameStateSingleton, which I don't want to retrieve every time explicitly with [[GameStateSingleton sharedMySingleton]getVariable], so I asked myself whether it is possible to do something like that :
In the interface file of my class, GameLayer I set up properties and variables like sharedHealth.
#interface GameLayer : CCLayer
{
int sharedHealth;
}
#property (nonatomic,assign) int sharedHealth;
and of course synthesize it in the implementation.
#synthesize sharedHealth;
In the initialization of GameLayer I would like to do something like :
sharedHealth = [self getCurrentHealth];
and add the corresponding method
-(int)getCurrentHealth{
int myHealth = [[GameStateSingleton sharedMySingleton]getSharedHealth];
return myHealth;
}
Is that possible ? From what I have experienced, I just seem to get crashes. How would I achieve my goal, to not always have to call the long method, as it always retrieves the same variable? There has to be a solution for this ...
You don't need an instance variable for that. You could just write a shortcut function like this:
- (int)sharedHealth {
return [[GameStateSingleton sharedMySingleton] getSharedHealth];
}
And where ever you need that value, you call [self sharedHealth].
You could also use a preprocessor macro instead. Just define this:
#define SharedHealth [[GameStateSingleton sharedMySingleton] getSharedHealth]
And then simply use that when you need the value.
Note, that in Objective-C you don't call getter methods "getVariable", but simply "variable". Mostly this is a convention, but if you start using KVC or KVO it's a rule you have to follow. So it's better to get used to it as soon as possible.
If it's just the repetitive typing that you're trying to avoid, you could use the old C way...
#define GAME_STATE [GameStateSingleton sharedMySingleton]
...and then...
int localValue = [GAME_STATE property];

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.