Say I am developing a tweak app, I want to create an instance of one Class whose header can't be imported, but I do know class name, class methods and instance methods How can I create it in class method with parameters?
Say this Class called MMClass with class method
+(instancetype)do:(NSString*)string for:(NSString *)antherString;
What I am doing is as below:
Class class = objc_getClass("MMClass");
Method initMethod = class_getClassMethod(class,
#selector(do:for:));
IMP imp = method_getImplementation(initMethod);
id instance = imp(class,#selector(do:for:),#"do",#"ye");
Is this right?
First, I'm not sure if I'm stating the obvious, but why not just create your own header with the declarations you want to use and import that (or just inline the declaration at the top of your file if you are only going to use it in one file)? and call the methods normally? instead of going through all this mess? All the compiler cares about is that it sees some declaration for the methods you want to call.
When you call the actual method implementation using a function pointer, you need to cast it to the right type of function pointer corresponding to the signature of the method:
Class class = objc_getClass("MMClass");
Method initMethod = class_getClassMethod(class, #selector(do:for:));
IMP imp = method_getImplementation(initMethod);
id (*foo)(Class, SEL, NSString *, NSString *) =
(id (*)(Class, SEL, NSString *, NSString *))imp;
id instance = foo(class, #selector(do:for:), #"do", #"ye");
But it's silly to get an IMP that you are only going to use once. Rather, you should just cast objc_msgSend to the desired function pointer type, and call that directly instead:
Class class = objc_getClass("MMClass");
id (*foo)(Class, SEL, NSString *, NSString *) =
(id (*)(Class, SEL, NSString *, NSString *))objc_msgSend;
id instance = foo(class, #selector(do:for:), #"do", #"ye");
Related
Apple doc says "NSInvocation does not support invocations of methods with either variable numbers of arguments or union arguments. "
i searched for hours ,some people says var_list works, but i tryed ,it does Not
but I think there may be a way to do the same thing (reflection) on variable params function,as i metioned ,[stringWithFormat:],
so , I found a way ,please readt the code bellow .
#interface INTObj : NSObject
#property (nonatomic, assign) int realvalue
#end
#interface FloatObj : NSObject
#property (nonatomic, assign) float realvalue
#end
// here ,the selectorName is only know in runtime
NSString *selectorName = #"stringWithFormat:";
SEL selector = NSSelectorFromString(selectorName);
typedef id (*Obj_Imp)(id,SEL,...);
Method md = class_getClassMethod(obj, selector); // here, obj means NSString
Obj_Imp fun = (Obj_Imp )method_getImplementation(md); // stringWithFormat:...
NSString *arg1 = #"hello %f %d";
FloatObj *fo = [[FloatObj alloc] init];
fo.realvalue = 11.3;
INTObj *io = [[INTObj alloc] init];
io.realvalue = 5;
NSObject *arr[3] = {arg1, fo,io};
// it cracks . exc_bad_Access code = 1
NSString *result = fun(obj , selector, arr[0], [arr[1] realvalue],[arr[2] realvalue]) ;
// it works but i cant do this ,because i don't know the type of the 4th parameters at Runtime
NSString *result = fun(obj , selector, arr[0],[(FloatObj *)arr[1] realvalue],[arr[2] realvalue])
why does the second calling of the function "fun" works while the first one cracks?
is there a better way to to do this?
This has nothing to do with NSInvocation or calling the method implementation directly. You should get the same undefined behavior if you called the method directly:
NSString *result = [NSString stringWithFormat:arr[0], [arr[1] realvalue], [arr[2] realvalue]];
or even a regular function:
NSLog(arr[0], [arr[1] realvalue], [arr[2] realvalue]);
In C (and Objective-C) every expression must have a compile-time type. The compiler needs to be know this compile-time type be able to compile the code correctly.
So let me ask you, what should be the compile-time type of [arr[1] realvalue]? Is it int? Is it float? The compiler will do different things depending on what type it is. If it is float for example, the C standard says that float passed to varargs will be promoted to double. The calling conventions for passing an int and a double in varargs are different (in fact, these two types have different sizes). And +[NSString stringWithFormat:] expects the compile-time type of the thing you pass to match the format specifier you give it in your format string, or there will be undefined behavior.
From your format string, it seems like you wanted the [arr[1] realvalue] argument to be float or double since you used %f. Since FloatObj is the class whose realvalue method returns float, it seems that casting arr[1] to FloatObj * is the right thing to do.
I'm new at Objective-C. I want to use global parameters like in C/C++
#define PARAM_1 1
How could I do this in Objective-C
The same way.
Objective-C is a superset of C, so your define is perfectly valid.
edited following comment
Rather than a define, which just performs textual substitution, you could use a static variable instead:
static NSNumber const * retrieveFriendRequestNumber = nil;
Which you can initialise in the class's initialiser method
+ (void)initialize {
retrieveFriendRequestNumber = #(2);
}
(Yes a bit long-winded, but an example of how to initialise a literal).
and then you can use it as:
[parameters setObject:retrieveFriendRequestNumber forKey:#"fcode"];
Alternatively, declare it as a static NSUInteger and convert it to an object when you use it:
static NSUInteger retrieveFriendRequest = 2;
And use it as:
[parameters setObject:#(retrieveFriendRequest) forKey:#"fcode"];
id is the type of the object; the type could have been NSArray * or NSString *, for example.
Class can either be NSArray * or NSString * or other object.
I can use them like follow
- (void)wantWriteAction:(id)sender {
}
- (void)wantWriteAction:(Class)sender {
}
I want to know the different between them.In what conditions can't use id?what condition can't use Class?
id represents an instance of any class. Class represents any class-- not an instance, but the class itself.
So id could be a specific instance of NSString or NSArray. You can call instance methods on it-- those which are shown with a - in the documentation, like -length or -stringByAppendingFormat. If the id is an NSString then its value might be #"foo".
Class could be the NSString class or the NSArray class. You can call class methods on it-- those which are shown with a + in the documentation, like +stringWithFormat. If the Class is NSString (note, not an NSString, but the NSString class) then it has no string value, because it's not a string. It's a class.
I'm struggling with the syntax of blocks. I need a block that takes no parameters and returns a string and I need to store that block in a property. So far, this is what I have...
I declare this property:
#property (nonatomic, copy) NSString * (^myBlockThatReturnsAString) ();
I assign the block like this:
someObject.myBlockThatReturnsAString = ^NSString * () {
return #"foo";
};
That all compiles fine.
I'm trying use it like this:
myString = someObject.myBlockThatReturnsAString;
but I get
-[__NSMallocBlock__ isEqualToString:]: unrecognized selector sent to instance 0xc16b3b0
Where am I going wrong?
What's going wrong is that the way you are attempting to run the block doesn't actually run it, it just returns the block object and attempts to assign it to an NSString variable.
This should work:
myString = someObject.myBlockThatReturnsAString();
Here is a great article about understanding the block syntax and why it is the way it is.
I have a SEL from a String .I can use "method_copyArgumentType" which is a runtime function to get the type of every argument,like this
char *arguType = method_copyArgumentType(m, i);//here m is a Method type,and i is the index of the argument
NSLog(#"method argNum=%d,%s",i,arguType);
by this way,if the argument type is a id,it will print"#",but i can't tell what kind of class it is,like a NSArray or a NSDictionary.
Is there a way to get the specific type of the argument?
There is not. The description of a method in a class does not record specific class types for arguments.