Objective-C: Get list of subclasses from superclass - objective-c

In Objective-C is there a way to ask a Class if there are any Subclass implementations.
I have a Base class which has multiple subclasses. I would like to loop through all the subclasses and perform a class selector on each of them.
Edit:
I have a set of classes that can process certain types of data. Each of the processors subclass a base class that provides methods that each processor needs.
Each class knows what data it can process and some classes can process certain types of data better than others.
I would like to have a class method on each class that would provide a response back to a factory class that says yes i can process that data, and give a indication of how well it can process it.
The factory would then make the decision on which class to instantiate based on which class says it can process the data the best.
I have also found this question from 2009 (I did search before I posted this but didn't find anything) Discover subclasses of a given class in Obj-C.
Edit 2:
The + (void)load method looks to be the perfect solution to what I am looking for. So I now have the following:
+ (void)registerSubclass:(Class)subclass {
NSLog(#"Registered %#", subclass);
}
In my base class the this is my subs.
+(void)load {
[BaseSwitch registerSubclass:[self class]];
}
This now displays a debug message for each of the subclasses.
My next question is (probably a stupid one), how do I store the classes that get registered in the registerSubclass method. Is there a way to have class variable that I can read later?
Edit 3:
Found some example code here A simple, extensible HTTP server in Cocoa
Which has left me with the following, seems pretty simple after all is said and done. But I thought I would put it here for future reference.
#implementation BaseSwitch
static NSMutableArray *registeredSubclasses;
+ (void)registerSubclass:(Class)subclass {
if (registeredSubclasses == nil) {
registeredSubclasses = [[NSMutableArray alloc] init];
}
[registeredSubclasses addObject:subclass];
NSLog(#"Registered %#", subclass);
}
+ (void)logSubclasses {
for (int i = 0; i < [registeredSubclasses count]; i++) {
NSLog(#"%#", [registeredSubclasses objectAtIndex:i]);
}
}
#end
Thanks for everyones suggestions, I will leave the question unanswered for a couple more days incase something else comes up.

This function gives you all subclasses of a class:
#import <objc/runtime.h>
NSArray *ClassGetSubclasses(Class parentClass)
{
int numClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
NSMutableArray *result = [NSMutableArray array];
for (NSInteger i = 0; i < numClasses; i++)
{
Class superClass = classes[i];
do
{
superClass = class_getSuperclass(superClass);
} while(superClass && superClass != parentClass);
if (superClass == nil)
{
continue;
}
[result addObject:classes[i]];
}
free(classes);
return result;
}
Taken from Cocoa with Love.

The example from Cocoa with Love can lead to EXC_I386_GPFLT, which stands for General Protection Fault. Instead of the do while loop, we should use a normal while loop to check if the superClass is valid.
#import <objc/runtime.h>
NSArray * ClassGetSubclasses(Class parentClass)
{
int numClasses = objc_getClassList(NULL, 0);
// According to the docs of objc_getClassList we should check
// if numClasses is bigger than 0.
if (numClasses <= 0) {
return [NSMutableArray array];
}
int memSize = sizeof(Class) * numClasses;
Class *classes = (__unsafe_unretained Class *)malloc(memSize);
if (classes == NULL && memSize) {
return [NSMutableArray array];
}
numClasses = objc_getClassList(classes, numClasses);
NSMutableArray<Class> *result = [NSMutableArray new];
for (NSInteger i = 0; i < numClasses; i++) {
Class superClass = classes[i];
// Don't add the parent class to list of sublcasses
if (superClass == parentClass) {
continue;
}
// Using a do while loop, like pointed out in Cocoa with Love,
// can lead to EXC_I386_GPFLT, which stands for General
// Protection Fault and means we are doing something we
// shouldn't do. It's safer to use a regular while loop to
// check if superClass is valid.
while (superClass && superClass != parentClass) {
superClass = class_getSuperclass(superClass);
}
if (superClass) {
[result addObject:classes[i]];
}
}
free(classes);
return result;
}
Check out the following GitHub issues for reference:
Sentry Cocoa
One Signal iOS SDK

You can never list subclasses of a class. In (almost) any programming language. This is one of the basic properties of Object Oriented Programming.
Consider changing your object model.
What you probably want is to create an abstract class and different subclasses but you shouldn't access the subclasses from the abstract class. You should create another object (Factory class) which registers the subclasses and selects the appropiate one when needed.
Note that you cannot efficiently register a class from the class itself. For a class code to be executed, the class has to be loaded first. That means, you have to import its header in some other class and that means that you are actually registering the class by importing its header.
There are two possible solutions:
Your factory class has to know the names of all subclasses (either at compile time or reading some configuration file).
Your factory class has a method to which anyone can pass the name of a class to be registered. This is the right solution if you want external libraries to register a new subclass. Then you can put the subclass registration code into the main header of the library.

Related

MacOS finding classes at launchtime

Is there a way to determine which classes are present at launch time?
I have a Swift OS-X app that offers an API to add functionality. Not dynamically though, everything is fixed at launch time.
But is it possible to find out which classes are present at launch, and then from there to call a certain (inherited) static operation on these classes?
Absent this possibility I will have to create an initialisation routine that must be updated every time a new subclass is added. I would like to avoid this.
Clarification: I have a protocol call it MyProtocol. At launch of the App I would like to call an operation from MyProtocol on all classes that implement MyProtocol.
After examining the runtime manual I have gotten as far as:
#import <Foundation/Foundation.h>
#include "Test.h"
#import <objc/objc-class.h>
void activateLaunchActions() {
// Get a list of all classes
int numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
Class *classes = NULL;
while (numClasses < newNumClasses) {
numClasses = newNumClasses;
Class newClasses[numClasses];
classes = newClasses;
newNumClasses = objc_getClassList(classes, numClasses);
}
// Get the protocol they have to confirm to
Protocol *prot = objc_getProtocol("MyProtocol");
// Get the selector to be called
SEL sel = sel_registerName("launchAction");
// Create the launchAction caller from objc_msgSend
typedef void (*send_type)(Class, SEL);
send_type callLauchAction = (send_type)objc_msgSend;
// Call the registration for all classes that confirm to the protocol
for (int i=0; i<numClasses; i++) {
if (class_conformsToProtocol(classes[i], prot)) {
callLauchAction(classes[i], sel);
}
}
}
The "prot" is always NULL. Hence the test later fails and the launchAction is never called.
I have read that protocol objects are not always present if they are not used by a class, however this protocol is used by several classes.
Any suggestions as how to fix this would be welcome.

Class issues: should I use everywhere self as class in objective c?

Wow, great issue I have found for myself.
What is it? The candy or the garlic?
something about Objective-C:
Are there any issues not to use 'self' in (+) - class methods as class?
in the deep of a class...
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
Ruby here:
For example, in Ruby everything is object and class is object of class Class and there is a good practice to rely on self:
class DateClass
# self is DateClass here, inside of class definition, uh
self.dateWithTimeInterval(interval)
self.dateWithTimeIntervalSince1970(interval)
end
end
Perl here:
Another example was found in perl oop deep: (thanks for this thread)
sub new {
my $proto = shift || die "Must pass a class or object into new()";
my $class = ref($proto) || $proto;
bless {}, $class;
}
So, in Perl and in Ruby guys always rely on $class refs
Maybe example with Perl code not obvious, but it happens all time. Programmers rely on $class reference and take class name with it. also, they can invoke some methods with it:
my $class = 'Class';
$class->new();
or
Class::->new()
After all...
Which pitfalls or caveats could you provide against usage self as class in objective-c?
Usually you use self whenever you can but of course, there are situations when referencing the class by [MyClass class] is desired. Almost all of the scenarios are related to inheritance.
For example, a creator method for a class A.
#implementation A
+ (id)createInstanceWithParam:(NSInteger)param {
return [[self alloc] initWithParam:param];
}
#end
Will work correctly even if we create a subclass B. However, if we decide to implement a class cluster, then we have to reference classes by names:
#implementation SomeDataStructure
+ (id)createInstanceWithType:(NSInteger)type {
if (type == 0) {
return [[DataStructureImpl1 alloc] init];
}
else if (type == 1) {
return [[DataStructureImpl2 alloc] init];
}
}
#end
Another example is the common example of +initialize
+ (void)initialize {
if (self == [MyClass class]) {
...perform initialization...
}
}
And of course, if you are overriding a method, then using self or using [MySelf class] can be a distinction between your overriden implementation and the original implementation. Although super could be used there, too.
TLDR:
self is preferred but be careful with subclasses/superclasses.
For understanding pros and cons of using self vs. class name let's consider one situation:
Class A is subclass of NSDate and implements method +(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval.
Class B is subclass of A and overrides implementation of +dateWithTimeIntervalSince1970:(NSTimeInterval)interval method that declared in NSDate.
Now let's consider two possible implementations of +(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval method in A:
1. Using self
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
if run [B dateWithTimeInterval:interval]; then self in above code is kind of B class and as expected custom implementation (in class B) for +(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval method would be called.
2. Using directly NSDate
+(NSDate*)dateWithTimeInterval:(NSTimeInterval)interval {
return [NSDate dateWithTimeIntervalSince1970:interval];
}
if run [B dateWithTimeInterval:interval]; then overridden implementation (in class B) would be ignored and instead of it: original implementation (in class NSDate) for +(NSDate*)dateWithTimeIntervalSince1970:(NSTimeInterval)interval method would be called. It's so because we directly send message to NSDate: [NSDate dateWithTimeIntervalSince1970:interval];.
This behavior is unexpected for developer.
For the same reason declare methods in such way:
+(instancetype)dateWithTimeInterval:(NSTimeInterval)interval {
return [self dateWithTimeIntervalSince1970:interval];
}
By using instancetype compiler will know what kind of object is returned by method-initializer. When you call [B dateWithTimeInterval:interval] it returns object of kind B but not NSDate.

Why does "conformsToProtocol" not check for "required" method implementations?

I am trying to enforce a "formal" #protocol, but cannot reliably test my classes/instances as to whether they ACTUALLY implement the protocol's "required" methods, vs. simply "declaring" that they conform to the protocol.
A complete example of my quandary…
#import <Foundation/Foundation.h>
#protocol RequiredProtocol
#required
- (NSString*) mustImplement; #end
#interface Cog : NSObject <RequiredProtocol> #end
#implementation Cog #end
#interface Sprocket : NSObject #end
#implementation Sprocket
- (NSString*) mustImplement
{ return #"I conform, but ObjC doesn't care!"; } #end
int main(int argc, char *argv[]) {
Protocol *required = #protocol(RequiredProtocol);
SEL requiredSEL = #selector(mustImplement);
void (^testProtocolConformance)(NSObject*) = ^(NSObject *x){
NSLog(#"Protocol:%#\n"
"Does %# class conform:%# \n"
"Do instances conform:%# \n"
"Required method's result:\"%#\"",
NSStringFromProtocol ( required ),
NSStringFromClass ( x.class ),
[x.class conformsToProtocol:required] ? #"YES" : #"NO",
[x conformsToProtocol:required] ? #"YES" : #"NO",
[x respondsToSelector:requiredSEL] ? [x mustImplement]
: nil );
};
testProtocolConformance ( Cog.new );
testProtocolConformance ( Sprocket.new );
}
Result:
Protocol:RequiredProtocol
Does Cog class conform:YES
Do instances conform:YES
Required method's result:"(null)"
Protocol:RequiredProtocol
Does Sprocket class conform:NO
Do instances conform:NO
Required method's result:"I conform, but ObjC doesn't care!"
Why is it that a class and it's instances that DO implement the #protocol's methods (Sprocket) return NO to conformsToProtocol?
And why does one that DOESN'T ACTUALLY conform, but SAYS that it DOES (Cog) return YES?
What is the point of a formal protocol if the declaration is all that's needed to feign conformance?
How can you ACTUALLY check for complete implementation of multiple #selectors without MULTIPLE calls to respondsToSelector?
#Josh Caswell.. Without diffing the two.. I'd guess that your response achieves similar effect to the category on NSObject I've been using in the meantime…
#implementation NSObject (ProtocolConformance)
- (BOOL) implementsProtocol:(id)nameOrProtocol {
Protocol *p = [nameOrProtocol isKindOfClass:NSString.class]
? NSProtocolFromString(nameOrProtocol)
: nameOrProtocol; // Arg is string OR protocol
Class klass = self.class;
unsigned int outCount = 0;
struct objc_method_description *methods = NULL;
methods = protocol_copyMethodDescriptionList( p, YES, YES, &outCount);
for (unsigned int i = 0; i < outCount; ++i) {
SEL selector = methods[i].name;
if (![klass instancesRespondToSelector: selector]) {
if (methods) free(methods); methods = NULL; return NO;
}
}
if (methods) free(methods); methods = NULL; return YES;
}
#end
Conforming to a protocol is just a "promise", you can't know if the receiver of conformsToProtocol: actually implements all the required methods. Is enough that you declare that the class conforms to the protocol using the angle brackets syntax, and conformsToProtocol: will return yes:
Discussion
A class is said to “conform to” a protocol if it adopts the protocol or inherits from another class that adopts it. Protocols are adopted by listing them within angle brackets after the interface declaration.
Full source: NSObject's conformsToProtocol: .
Protocols declarations have just the advantage that you can know at compile time if a class really adopts that required methods. If not, a warning will be given. I suggest to don't rely on conformsToProtocol:, but to use introspection instead. That is, verify if a class/object implements a method by calling instancesRespondToSelector: / respondsToSelector: :
+ (BOOL)instancesRespondToSelector:(SEL)aSelector;
- (BOOL)respondsToSelector:(SEL)aSelector;
What compiler are you using? Xcode/Clang issues 2 warnings and 1 error...
Think of a protocol as a club with membership requirements. Asking whether someone is a member of the club, provable by them having a membership card (NSObject<ReqiredProtocol>), should tell you that a person meets those requirements. However the lack of a membership doesn't mean they don't meet the requirements.
E.g. someone (Sprocket) might meet all the requirements to join but choose not to. Someone else (Cog) may failed to meet the requirements but a sloppy administrator might let them in.
The latter is why I asked about the compiler (the sloppy administrator ;-)). Try your code as entered on Xcode 4.6.3/Clang 4.2 produces warnings and errors (as does using GCC 4.2):
The warnings state that Cog fails to implement the required methods;
The error complains about [x mustImplement] as x is not known to have the required method as it is of type NSObject - you need to cast to remove that, just [(id)x mustImplement] will do as you've already tested the method exists.
In summary, you can only rely on conformsToProtocol if you know the originator of the code didn't ignore compiler warnings - the checking is done at compile time.
Addendum
I missed the last sentence of your question. If you wish to discover whether a class meets the requirements of a protocol, even if it doesn't declare that it does, e.g. Sprocket above (or if you are obtaining code from folk who ignore compiler warnings - the Cog author above), then you can do so using the facilities of the Obj-C runtime. And you'll only have to write one call to repsondsToSelector...
I just typed in the following and quickly tested it on your sample. It is not throughly tested by any means, caveat emptor etc. Code assumes ARC.
#import <objc/runtime.h>
#interface ProtocolChecker : NSObject
+ (BOOL) doesClass:(Class)aClass meetTheRequirementsOf:(Protocol *)aProtocol;
#end
#implementation ProtocolChecker
+ (BOOL) doesClass:(Class)aClass meetTheRequirementsOf:(Protocol *)aProtocol
{
struct objc_method_description *methods;
unsigned int count;
// required instance methods
methods = protocol_copyMethodDescriptionList(aProtocol, YES, YES, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![aClass instancesRespondToSelector:methods[ix].name])
{
free(methods);
return NO;
}
}
free(methods);
// required class methods
methods = protocol_copyMethodDescriptionList(aProtocol, YES, NO, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![aClass respondsToSelector:methods[ix].name])
{
free(methods);
return NO;
}
}
free(methods);
// other protocols
Protocol * __unsafe_unretained *protocols = protocol_copyProtocolList(aProtocol, &count);
for (unsigned int ix = 0; ix < count; ix++)
{
if (![self doesClass:aClass meetTheRequirementsOf:protocols[ix]])
{
free(protocols);
return NO;
}
}
free(protocols);
return YES;
}
#end
You should of course want to know exactly how this works, especially the * __unsafe_unretained * bit. That is left as an exercise :-)
CRD is right; the compiler tells you about actual conformance, and it should be listened to. If that's being ignored, the runtime doesn't have any built-in method to double-check. Classes maintain internal lists of protocol objects internally; conformsToProtocol: just looks at that.
At the risk that someone is going to come along and tell me to stop fiddling with the ##(%!^& runtime again, if you really truly need to check actual implementation, this is one way you can do so:
#import <objc/runtime.h>
BOOL classReallyTrulyDoesImplementAllTheRequiredMethodsOfThisProtocol(Class cls, Protocol * prtcl)
{
unsigned int meth_count;
struct objc_method_description * meth_list;
meth_list = protocol_copyMethodDescriptionList(p,
YES /*isRequired*/,
YES /*isInstanceMethod*/,
&meth_count);
/* Check instance methods */
for(int i = 0; i < meth_count; i++ ){
SEL methName = meth_list[i].name;
if( ![class instancesRespondToSelector:methName] ){
/* Missing _any_ required methods means failure */
free(meth_list);
return NO;
}
}
free(meth_list);
meth_list = protocol_copyMethodDescriptionList(p,
YES /*isRequired*/,
NO /*isInstanceMethod*/,
&meth_count);
/* Check class methods, if any */
for(int i = 0; i < meth_count; i++ ){
SEL methName = meth_list[i].name;
if( ![class respondsToSelector:methName] ){
free(meth_list);
return NO;
}
}
free(meth_list);
return YES;
}
If I had a hammer...
All of these answers are good. To them, I would add one more point: calling conformsToProtocol: is almost always a mistake. Because it tells whether the class says that it conforms to the protocol, rather than whether it actually provides specific methods:
It is possible to create a class that claims to conform, but does not, by silencing various warnings, resulting in crashes if you assume that a required method exists.
It is possible to create a class that conforms to the protocol but does not claim to do so, resulting in methods not getting called on a delegate even though they exist.
It can lead to programming errors creeping in when the protocol changes, because your code checks for conformance to a protocol before calling a method that used to be required, but no longer is.
All of these issues can cause unexpected behavior.
IMO, if you want to know if a class handles a method, the safest approach is to explicitly ask it if it handles that method (respondsToSelector:), rather than asking it if it conforms to a protocol that just happens to contain that method.
IMO, conformsToProtocol: should really have been a function in the Objective-C runtime instead of being exposed on NSObject, because it generally causes more problems than it solves.

Is it okay to return a subclass from a class constructor that uses instancetype?

I have a class method in a category to construct a Cocoa collection in some way that the built-in initializers don't allow. Due to the limited initializer functionality, I have to use the mutable version of the collection to actually build it. Here's an example for NS{Mutable}IndexSet:
#implementation NSIndexSet (WSSNonContiguous)
+ (instancetype)WSSIndexSetFromMask:(NSUInteger)mask
{
NSMutableIndexSet * set = [NSMutableIndexSet indexSet];
for( NSUInteger i = 0; i < (sizeof(NSUInteger) * 8); i++ ){
if( mask & (1l << i) ){
[set addIndex:i];
}
}
return set;
}
My return type is sometimes a lie here -- there's always a mutable collection being returned, whether the user is requesting an immutable version or not.
Is it still appropriate to use instancetype in cases like this, or should I go with id? If I do use instancetype, should I also be explicitly re-creating the collection:
// Ick?
return [[self alloc] initWithIndexSet:set];
to make sure an immutable copy is returned when the call is +[NSIndexSet WSSIndexSetFromMask:]?
Everything is okay:
NSIndexSet *set = [[NSIndexSet WSSIndexSetFromMask:0] addIndex:0];
No visible #interface for 'NSIndexSet' declares the selector 'addIndex:'
instancetype says to the sender, that you return a instance of the receivers type even it is a subtype. For the sender it is a NSIndexSet, because it is send to the class object of NSIndexSet.
An introspection that way, that someone looks to the return type and sees a subclass and takes any advantage out of this information, is malformed. The contract is build with the return type and this is in this case NSIndexSet.

How to get the class that the method is defined, not that of the instance that the method is called?

[self class] returns the Class of the instance of the method being called, but is there a way to get the Class that the method is defined? Suppose Class B extends A, and b is an instance of B, I want a method in A that returns A not B, even when called from b.
edited:
I trying to create a NSObject category that has -(void)releaseProperties method, which fetches all properties defined in that class and set nil for the non-readonly object properties.
- (void)releaseProperties {
unsigned int c = 0;
objc_property_t *properties = class_copyPropertyList([self class], &c);
for(unsigned int i = 0; i < c; i++) {
objc_property_t property = properties[i];
NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
NSString *propertyType = [NSString stringWithUTF8String:property_getAttributes(property)];
if([propertyType hasPrefix:#"T#"] // is an object
&& [propertyType rangeOfString:#",R,"].location == NSNotFound // not readonly
) {
[self setValue:nil forKey:propertyName];
NSLog(#"%#.%# = %#", NSStringFromClass(cls), propertyName, [self valueForKey:propertyName]);
}
}
free(properties);
}
I want to use this method in the dealloc method, but class_copyPropertyList([self class], &c) will not return properties defined in it's superclass, so the super-dealloc chain doesn't work well. So, instead of passing [self class], I wanted to pass the class that the specific dealloc method is being called.
I don't think there's a direct way of doing this, but you can call class_getMethodImplementation_stret with the current class to get the function pointer for the method that would be called. Then walk your superclasses, calling the same function with them until it returns something different. The previous superclass will be the one that is providing the implementation for your class.
Edit: Sorry, I may have misread the question. If you are looking for the first superclass in the hierarchy that defines a method with that signature, then you can just walk the superclasses calling respondsToSelector: until one of them doesn't. The method I describe above is to find the superclass providing the implementation that is inherited, not the definition.
For example, class A could define foo:, then class B (which is a subclass of A) could override it, then class C (which is a subclass of B) could ask where foo: comes from. If you want the class that provides the definition, you want A, and should use the second approach I describe. If you want the class that provides the implementation, you want B and should use the first approach I describe.
I have a feeling that [super class] might work for you.
And if you call "[super ..." (fill in the blank with whatever you want to call) within B, you'll be calling into a method that lives in A.
Class A can just provide a method like:
- (Class) classA
{
return [A class];
}
That's not generalizable, but your question insists on a non-generalizable answer.
It's a pretty bizarre thing to want. It suggests a problem with your design. May I ask why you want it? What problem are you trying to solve?