Calling a static method in an unknown type of class - objective-c

I have an interesting problem where I am trying to call class methods on an class which I essentially know nothing about in my test method. I can inspect its inheritance and any protocols it may implement but can't see an easy way to just call a method on it without getting tied up with an NSInvocation. The code below, albeit crudely, tries to demonstrate the problem I am having.
#interface ClassA : NSObject
+ (Class)classIsPartialClassOf;
#end
#implementation ClassA
+ (Class)classIsPartialClassOf {
return [NSString class];
}
#end
#interface ClassB : NSObject
#end
#implementation ClassB
- (id)init {
[ClassB testClass:[ClassA class]];
}
+ (void)testClass:(Class)classDecl {
/* obviously if you know the type you can just call the method */
[ClassA classIsPartialClassOf];
/* but in my instance I do not know the type, obviously there are no classmethods to perform selector such as the fictional one below */
[classDecl performSelector:#selector(classIsPartialClassOf)];
}
#end
Methods for getting implementations seem to return instance variants and I can't get them to fire on the static class itself.
Are my options limited to invocations or have I missed something obvious and should kick myself?
Thank you in advance for your help.

What is the problem? Your code
[classDecl performSelector:#selector(classIsPartialClassOf)];
should work. As will (simpler to write)
[classDecl classIsPartialClassOf];
Class objects are objects. And class methods are simply methods called on a class object.

"Methods for getting implementations seem to return instance variants and I can't get them to fire on the static class itself."
Then use objc_getMetaClass("ClassName") instead of objc_getClass. Class objects are objects themselves and are instances of their metaclass. If you pass the metaclass object to e. g. class_getMethod(), everything will be fine.

Related

Inheritance in class methods

I have the following class:
#interface ClassA
+ (void)method1;
+ (void)method2;
#end
#implementation ClassA
+ (void)method2 {
[self method1];
}
#end
And one that inherits from it:
#interface ClassB : ClassA
#end
#implementation ClassB
+ (void)method1 {
NSLog(#"ClassB");
}
#end
If in an specific segment of code I do:
[ClassB method2];
It will throw an error cause it will try to call [ClassA method1], but this class doesn't implement that method. Is it even possible somehow that call is make to ClassB and not to ClassA? Scenario is: I have a base class with some utility class methods that relate in between them. Children don't need to implement those, but need to implement one that is used inside some of those methods. But once the flow goes into the parent, when it calls this method, it calls the parent one - which is not implemented.
You have multiple problems:
First
First point deleted thanks to #rmaddy comments.
Second
Your methods return a instancetype variable, while they don't: if you want to leave your implementation like that, change your method to return void
Third
You forgot implementation of + (instancetype)method1; so this code it not valid.

Does super work only with methods

Being new to objectiveC I was experimenting with the super keyword. I wanted to know if the super keyword is only used for calling the base class method.
Consider the following code
#interface foo_base : NSObject
{
int int_ivar;
}
-(void) base_method;
-(void) shared_method;
#end
#interface foo_der : foo_base
-(void) der_method;
-(void) shared_method;
#end
In the implementation of shared_method if I try doing this
#implementation foo_der
- (void) shared_method
{
[super shared_method]; //Works ok call base class method
int_ivar =23; //Works ok (Access base class ivar)
self->int_ivar = 23; //Works ok (Access base class ivar)
super->int_ivar=23; //Error- Why ? is super only limited to methods?
}
...
...
#end
Is the super keyword only used for calling the base class methods from the derived class ?
Yes, super is only for invoking methods. super is not really an object pointer. If it were, it would have the same pointer value as self. They refer to the same thing. It's just that super changes the lookup of the method implementation.
When you message self, the search for the implementation for the message you sent begins in the actual class of the object pointed to by self. That can be different than the static type of the self pointer.
When you message super, the search begins in the superclass of the class in whose implementation the message-to-super statement appears. That's the only purpose of super.

How can an Objective-C Class be tested to determine if it responds to a static selector (a class method)?

This is most easily explained with a brief example. Let's say I have the following protocol and class definitions:
#protocol ProtocolA <NSObject>
#optional
+ (BOOL)methodA;
#end
#interface ClassA : NSObject <ProtocolA>
#end
ClassA may or may not define methodA. If I was working with an instance of ClassA and an instance method, I could test the instance with respondsToSelector:. In this situation, however, I cannot think of any clean way to determine if ClassA defines (responds to) methodA.
EDIT:
I was silly and did not make my example specific enough, which meant the answer to the question was not exactly the solution to my problem -- so I am including a bit more code and the warning I am getting:
Class <ProtocolA> classRef = [ClassA class];
if([classRef respondsToSelector:#selector(methodA)]) {}
The above code throws the following warning:
" Instance method 'respondsToSelector:' found instead of class method 'respondsToSelector:'"
I only just now noticed that if I explicitly cast classRef to (Class) then the warning goes away. I still find that odd.
[[instance class] respondsToSelector:#selector(methodA)]
Every instance of a class has a pointer to it's class object which can be retrieved by calling class. This object (classes are objects in Objective C) can be probed with respondsToSelector: just like any other object.

Sharing common method implementation between classes implementing the same protocol in Objective C

I have a protocol.
MyProtocol.h:
#protocol MyProtocol
#property(nonatomic, retain) NSString* someString;
- (void)doesSomethingWithSomeString;
#end
And 2 classes that implement the same protocol. For some reason the 2 classes cannot inherit from the same base class. E.g. 1 of them might need to inherit from NSManagedObject (Core Data class in Apple's Cocoa framework) while the other shouldn't.
Class1.h:
#interface Class1: NSObject<MyProtocol> {
NSString* someString;
}
//Some method declarations
#end
Class1.m
#implementation Class1
#synthesize someString;
- (void)doesSomethingWithSomeString {
//don't use property here to focus on topic
return [[self someString] capitalizedString];
}
//Method definitions for methods declared in Class1
#end
Class2.h:
#interface Class2: SomeOtherClass<MyProtocol> {
NSString* someString;
}
//Some method declarations
#end
Class2.m
#implementation Class2
#synthesize someString;
// This is exactly the same as -doesSomethingWithSomeString in Class1.
- (void)doesSomethingWithSomeString {
//don't use property here to focus on topic
return [[self someString] capitalizedString];
}
//Method definitions for methods declared in Class2
#end
How can I avoid the duplication of -doesSomethingWithSomeString? (I guess I need something like categories for multiple classes).
Update:
There has been some suggestions of a helper class and delegating calls from Class1 and Class2 to it. It might be a good approach generally, especially if the methods are long.
In this case, I am looking at Class1 inheriting from NSObject and Class2 inheriting from NSManagedObject. The latter being a base class that Class2 has to subclass from, as a model/entity within the Apple Core Data framework.
So while delegation to a third class is one way to do this, there needs to be a lot of boilerplate delegation wrapper code for what amounts to many short 1-2 methods in the 3rd class. i.e. high boilerplate delegation code to actual code ration.
Another point is, as this is a model class, the common code mostly acts on ivars/properties, the delegation class will end up written almost like global C functions..
You can create a helper class an then use it from Class1 and Class2, and then only the call to the method on the helper class will be duplicated
This situation indicates that your Class1 and Class2 are not fully factored into classes that handle just one concern. The fact that you have a common implementation indicates that there should be a third class that provides that implementation and to which Class1 and Class2 can delegate that concern. In other words, this is a case for composition instead of inheritance.
Update
If it doesn't make sense to delegate to a class, don't forget that Objective-C is a superset of C. There's nothing stoping you from implementing a library of C functions that you can call from both classes to encapsulate the common behavior. If you're committed to conveniences like NSAssert et al., you can always implement them as class methods on a utility class or category on NSObject.
Personally I think this should be duplicated. You will likely need to customise one of them eventually and then you will be annoyed at all the work you did to prevent the duplication. Anything large can go into categories on the objects you are working with similar to whats going on inside capitalizedString.

Is it possible to declare a method as private in Objective-C?

Is it possible to declare a method as private in Objective-C?
If you're working in Objective-C 2.0, the best way to create methods that are "hard" for others to call is to put them in a class extension. Assuming you have
#interface MyClass : NSObject {
}
- (id)aPublicMethod;
#end
in a MyClass.h file, you can add to your MyClass.m the following:
#interface MyClass () //note the empty category name
- (id)aPrivateMethod;
#end
#implementation MyClass
- (id)aPublicMethod {...}
- (id)aPrivateMethod {...} //extension method implemented in class implementation block
#end
The advanage of a class extension is that the "extension" methods are implemented in the original class body. Thus, you don't have to worry about which #implementation block a method implementation is in and the compiler will give a warning if the extension method is not implemented in the class' #implementation.
As others have pointed out, the Objective-C runtime will not enforce the privateness of your methods (and its not too hard to find out what those methods are using class dump, even without the source code), but the compiler will generate a warning if someone tries to call them. In general, the ObjC community takes a "I told you not to call this method [by putting it in a private class extension or category or just by documenting that the method is private] and you called it anyways. Whatever mess ensues is your fault. Don't be stupid." attitude to this issue.
No, any object can send any message to any other object. You can, however, put the method in a category that's part of the class's implementation file. That way, you'll get a "Class may not implement this method" warning if you try to call it anywhere else. That's the normal way of making a method "private."
There is nothing that will prevent the method being called (since objective-c is message based anything can be sent any message), but you can declare them outside of the header so they are not visible and the compiler will generate warnings if used.
This works for both class and instance methods.
E.g.
#import "SomeClass.h"
// Interface for hidden methods
#interface SomeClass (hidden)
+(void) hiddenClassMethod;
-(void) hiddenInstanceMethod;
#end
Note: Do NOT declare variables like this or they will become class-variables - e.g. only one variable will be used by all instances.
You can do so by using categories. I've got a fuller description in my answer to this SO question.
As has been said, you can't stop anyone sending a message to a selector, but by using categories you can reduce the visibility of these functions.
Also, you can have more than one category extending a class. So, by using informative category names you can group private functions into related blocks, improving the self-documenting nature of your code.
As others mentioned, you can't have code that's
a method, and
impossible to call from outside a class.
Folks have already pointed out that you can abandon point 2, and get a method that's hard-but-not-impossible to call. Alternatively, why not abandon point 1?
static id myPrivateMethod(MyObject *me, int arg1, id arg2) { ... }
Now the code can only be called from within same file. You don't get any of the magic private-member access you can get with a method, so this is by no means a perfect solution. But there's no better way to achieve privacy.
To implement hidden methods (instance and/or class)
// ===========================
// = File: SomeClass.m
// ===========================
#import "SomeClass.h"
// =================================
// = Interface for hidden methods
// =================================
#interface SomeClass (hidden)
-(void) hiddenInstanceMethod;
#end
// ================================
// = Implementation for SomeClass
// ================================
#implementation SomeClass
-(void) hiddenInstanceMethod
{
printf( "Hidden instance method\n" );
}
-(void) msg
{
printf("Inside msg()...\n");
[self hiddenInstanceMethod];//private method calling
}
#end
http://macdevelopertips.com/objective-c/private-methods.html
reffer this link it will be helpful .