Crash when processing __NSAtom class object - objective-c

Hi I'm using this answer to get list of class to automatically build some structure.
My code looks like that:
NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity: 32];
Class* classes = NULL;
int numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0 ) {
classes = (Class*)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int index = 0; index < numClasses; index++) {
Class nextClass = classes[index];
if ([nextClass isSubclassOfClass: BaseCmd.class] &&
![BaseCmd isSubclassOfClass: nextClass]) {
BaseCmd *cmd = [nextClass new];
result[cmd.name] = cmd;
}
}
free(classes);
}
return result;
So modification from answer is quite simple. It does work quite nicely until __NSAtom class is processed (index = 1548 numClasses = 7628 so it is not out of bounds problem).
When this __NSAtom class is reached there is a crash. Logs show:
*** NSForwarding: warning: object 0x7fff74978938 of class '__NSAtom' does not implement methodSignatureForSelector: -- trouble ahead
*** NSForwarding: warning: object 0x7fff74978938 of class '__NSAtom' does not implement doesNotRecognizeSelector: -- abort
Crash comes from condition isSubclassOfClass.
Why it doesn't work? How can I fix it?
I'm using OS X Yosemite.

+[NSObject isSubclassOfClass:] is a class method for NSObject and not all classes are subclasses of NSObject.
It seems as if you have find private class that is not a subclass of NSObject, so it requires a more delicate handling for checking for inheritance. Try:
BOOL isSubclass(Class child, Class parent) {
for (Class c = child; c != Nil; c = class_getSuperclass(c)) {
if (c == parent) {
return YES;
}
}
return NO;
}

Related

realloc() & ARC

How would I be able to rewrite the the following utility class to get all the class string values for a specific type - using the Objective-c runtime functions as shown below?
The ARC documentation specifically states that realloc should be avoided and I also get the following compiler error on this this line:
classList = realloc(classList, sizeof(Class) * numClasses);
"Implicit conversion of a non-Objective-C pointer type 'void *' to '__unsafe_unretained Class *' is disallowed with ARC"
The the below code is a reference to the original article which can be found here.
+ (NSArray *)classStringsForClassesOfType:(Class)filterType {
int numClasses = 0, newNumClasses = objc_getClassList(NULL, 0);
Class *classList = NULL;
while (numClasses < newNumClasses) {
numClasses = newNumClasses;
classList = realloc(classList, sizeof(Class) * numClasses);
newNumClasses = objc_getClassList(classList, numClasses);
}
NSMutableArray *classesArray = [NSMutableArray array];
for (int i = 0; i < numClasses; i++) {
Class superClass = classList[i];
do {
superClass = class_getSuperclass(superClass);
if (superClass == filterType) {
[classesArray addObject:NSStringFromClass(classList[i])];
break;
}
} while (superClass);
}
free(classList);
return classesArray;
}
Your help will be much appreciated.
ARC forces you to be more explicit with you memory management. In this case, you just need to explicitly cast the output of realloc:
classList = (Class *)realloc(classList, sizeof(Class) * numClasses);

Get all subclasses of UIView in runtime in Objective-c

Is is possible in Objective-c runtime to get an array of all subclasses of UIView class?
Here's the code that prints names of all UIView subclasses: (How to get list of all classes available at runtime can be found here). Note also that this code will print only direct UIView subclasses, if you want to go further down the hierarchy you'll probably need to call listed code recursively with desired superclass as a parameter.
Class * classes = NULL;
int numClasses = objc_getClassList(NULL, 0);
if (numClasses > 0 )
{
classes = malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int i = 0; i < numClasses; ++i){
if (class_getSuperclass(classes[i]) == [UIView class]){
NSLog(#"%#", NSStringFromClass(classes[i]));
}
}
free(classes);
}

Why can some methods (-retainWeakReference, -allowsWeakReference, +load, +initialize) on class NSObject not be added to other classes at runtime?

It is straightforward at runtime to create a copy MyNSObject of the Class NSObject:
First, create a new class pair.
Class MyNSObject = objc_allocateClassPair(nil, "MyNSObject", 0);
Second read the methods, protocols, and ivars from NSObject and add them to the new class.
uint instanceMethodCount;
Method *instanceMethodArray = class_copyMethodList([NSObject class], &instanceMethodCount);
for (int i = 0; i < instanceMethodCount; i++) {
Method method = *(instanceMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
BOOL success = class_addMethod(MyNSObject, selector, implementation, types);
}
free(instanceMethodArray);
uint protocolCount;
Protocol **protocolArray = class_copyProtocolList([NSObject class], &protocolCount);
for (int i = 0; i < protocolCount; i++) {
Protocol *protocol = *(protocolArray + i);
BOOL success = class_addProtocol(MyNSObject, protocol);
}
free(protocolArray);
uint ivarCount;
Ivar *ivarArray = class_copyIvarList([NSObject class], &ivarCount);
for (int i = 0; i < ivarCount; i++) {
Ivar ivar = *(ivarArray + i);
const char *name = ivar_getName(ivar);
const char *typeEncoding = ivar_getTypeEncoding(ivar);
NSUInteger size, alignment;
NSGetSizeAndAlignment(typeEncoding, &size, &alignment);
BOOL success = class_addIvar(MyNSObject, name, size, alignment, typeEncoding);
}
free (ivarArray);
Third, read the methods from the metaclass of NSObject and add them to the new metaclass.
uint classMethodCount;
Method *classMethodArray = class_copyMethodList(object_getClass([NSObject class]), &classMethodCount);
for (int i = 0; i < classMethodCount; i++) {
Method method = *(classMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
BOOL success = class_addMethod(object_getClass(MyNSObject), selector, implementation, types);
}
free(classMethodArray);
And finally, register the class pair.
objc_registerClassPair(MyNSObject);
Well, it's almost that straightforward. There are a couple of problems with this. Well, a couple of couples. If we were to add the following lines at the end but within the first for block
if (!success) {
NSLog(#"unable to add method with selector named %# to class MyNSObject", NSStringFromSelector(selector));
}
and the following lines at the end but within the last for block
if (!success) {
NSLog(#"unable to add method with selector name %# to metaclass MyNSObject", NSStringFromSelector(selector));
}
Then we would see the following output:
unable to add method with selector name retainWeakReference to class MyNSObject
unable to add method with selector name allowsWeakReference to class MyNSObject
unable to add method with selector name load to metaclass MyNSObject
unable to add method with selector name initialize to metaclass MyNSObject
What is going on here? Do classes (resp. metaclasses) implement retainWeakReference and allowsWeakReferenc (resp. load and initialize) "out of the box"?
References:
1. Cocoa with Love - What is a meta-class in Objective-C?
2. Stack Overflow - Justin Spahr-Summers response to "How can one obtain the sizeof a type for which one has an encoding?"
NSObject is an even more interesting beast than expected. Typically one thinks about the map
method_getName: Method -> SEL
as being one-to-one. I.e one usually thinks that method_getName(methodA) == method_getName(methodB) just in case methodA == methodB. One is encouraged to think this: one cannot create a class during coding via #interface which has multiple methods with the same selector, nor can one add two methods with the same selector to a class using class_addMethod() during runtime.
However, it is evidently possible to do it by hand. The following code demonstrates this. This code gets all the instance methods on NSObject and prints out each one named either "retainWeakReference" or "allowsWeakReference" and then gets all the class methods on NSObject and prints out each one named either "initialize" or "load".
uint NSObjectInstanceMethodCount;
Method *NSObjectInstanceMethodArray = class_copyMethodList([NSObject class], &NSObjectInstanceMethodCount);
for (int i = 0; i < NSObjectInstanceMethodCount; i++) {
Method method = *(NSObjectInstanceMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (strcmp(selector, "retainWeakReference") == 0 || strcmp(selector, "allowsWeakReference") == 0) {
NSLog(#"NSObject implements method(%s,%p,%s)", selector, implementation, types);
}
}
uint NSObjectClassMethodCount;
Method *NSObjectClassMethodArray = class_copyMethodList(object_getClass([NSObject class]), &NSObjectClassMethodCount);
for (int i = 0; i < NSObjectClassMethodCount; i++) {
Method method = *(NSObjectClassMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (strcmp(selector, "initialize") == 0 || strcmp(selector, "load") == 0) {
NSLog(#"metaNSObject implements method(%s,%p,%s)", selector, implementation, types);
}
}
The output is not what one might, aside from the preceding build-up, have expected:
NSObject implements method(retainWeakReference,0x7fff8a120b1f,c16#0:8)
NSObject implements method(allowsWeakReference,0x7fff8a120b05,c16#0:8)
NSObject implements method(retainWeakReference,0x7fff80ad6db0,c16#0:8)
NSObject implements method(allowsWeakReference,0x7fff80ad6d90,c16#0:8)
metaNSObject implements method(load,0x7fff8a09e4f2,v16#0:8)
metaNSObject implements method(initialize,0x7fff8a00cb89,v16#0:8)
metaNSObject implements method(load,0x7fff80a57670,v16#0:8)
metaNSObject implements method(initialize,0x7fff80a133d0,v16#0:8)
So, as is now evident, NSObject has two implementations for each of the selectors -retainWeakReference, -allowsWeakReference, +load, and +initialize. These are the only four methods on NSObject for which there are multiple implementations, which is demonstrated by the fact that these were the only four reported by the code in the question as being unable to be added to MyNSObject.
A statement which gets close to counting as an answer to the question then is that you can't add multiple methods with the same selector to a class created at runtime via class_addMethod(). In particular, though, no, no methods are implemented by a class created at runtime with objc_allocateClassPair() "out of the box".

How can I find a class which inherit from a particular class from my Class list?

I get the list of all classes of my application.
I want to find each Class from my list which inherits from MySpecificWrapperClass.
int numClasses = objc_getClassList(NULL, 0);
Class *classes = malloc(sizeof(Class) * numClasses);
objc_getClassList(classes, numClasses);
for (int i = 0; i < numClasses; i++) {
Class class = classes[i];
if( isThisClassInheritsFrom(class,MySpecificWrapperClass )){
MySpecificWrapperClass o = [[class alloc]init];
...
}
}
free(classes);
Dose somebody know how to do that?
Thank for help.
Fred
There may be a better solution, but brute force should do it. class_getSuperclass returns the Class object for a given Class object's superclass. When you get to the root class, it returns Nil.
for (int i = 0; i < numClasses; i++) {
Class class = classes[i];
Class superclass = class_getSuperclass(class);
while( superclass != Nil ){
if( superclass == MySpecificWrapperClass ){
// Got one!
break;
}
superclass = class_getSuperclass(superclass);
};
}
This is assuming that you want to check the entire hierarchy for a given class, i.e., you want every class that has your class anywhere in its ancestors. If you only care about direct subclasses, obviously, you only need to call class_getSuperclass once.
To test if a class is inherits of your class, try
if ([obj isKindOfClass: MySpecificWrapperClass])
You can check if a class is a subclass of another class with the isSubclassOfClass: method defined by NSObject.
NSObject class reference

List selectors for Objective-C object

I have an object, and I want to list all the selectors to which it responds. It feels like this should be perfectly possible, but I'm having trouble finding the APIs.
This is a solution based on the runtime C functions:
class_copyMethodList returns a list of class methods given a Class object obtainable from an object.
#import <objc/runtime.h>
[..]
SomeClass * t = [[SomeClass alloc] init];
int i=0;
unsigned int mc = 0;
Method * mlist = class_copyMethodList(object_getClass(t), &mc);
NSLog(#"%d methods", mc);
for(i=0;i<mc;i++)
NSLog(#"Method no #%d: %s", i, sel_getName(method_getName(mlist[i])));
/* note mlist needs to be freed */
I think usually you'll want to do that in the console, instead of cluttering your code with debug code. This is how you can do that while debugging in lldb:
(Assuming an object t)
p int $num = 0;
expr Method *$m = (Method *)class_copyMethodList((Class)object_getClass(t), &$num);
expr for(int i=0;i<$num;i++) { (void)NSLog(#"%s",(char *)sel_getName((SEL)method_getName($m[i]))); }
This is also possible with Swift:
let obj = NSObject()
var mc: UInt32 = 0
let mcPointer = withUnsafeMutablePointer(&mc, { $0 })
let mlist = class_copyMethodList(object_getClass(obj), mcPointer)
print("\(mc) methods")
for i in 0...Int(mc) {
print(String(format: "Method #%d: %s", arguments: [i, sel_getName(method_getName(mlist[i]))]))
}
Output:
251 methods
Method #0: hashValue
Method #1: postNotificationWithDescription:
Method #2: okToNotifyFromThisThread
Method #3: fromNotifySafeThreadPerformSelector:withObject:
Method #4: allowSafePerformSelector
Method #5: disallowSafePerformSelector
...
Method #247: isProxy
Method #248: isMemberOfClass:
Method #249: superclass
Method #250: isFault
Method #251: <null selector>
Tested with the 6s simulator running iOS 9.2, Xcode Version 7.2 (7C68).
Taking inspiration from JAL's answer, in Swift you can do:
extension NSObject {
var __methods: [Selector] {
var methodCount: UInt32 = 0
guard
let methodList = class_copyMethodList(type(of: self), &methodCount),
methodCount != 0
else { return [] }
return (0 ..< Int(methodCount))
.flatMap({ method_getName(methodList[$0]) })
}
}
ARC realization
SomeClass *someClass = [[SomeClass alloc] init];
//List of all methods
unsigned int amountMethod = 0;
Method *methods = class_copyMethodList(someClass, &amountMethod);
for (unsigned int i = 0; i < amountMethod; i++) {
Method method = methods[i];
printf("\t method named:'%s' \n", sel_getName(method_getName(method)));
}
free(methods);
Something like this should work (just put it in the object you're curious about). For example if you have an object that's a delegate and want to know what 'hooks' are available this will print out messages to give you that clue:
-(BOOL) respondsToSelector:(SEL)aSelector {
printf("Selector: %s\n", [NSStringFromSelector(aSelector) UTF8String]);
return [super respondsToSelector:aSelector];
}
Note that I discovered this in the iPhone Developer's Cookbook so I can't take credit! For example output I get from a UIViewController that implements the protocols <UITableViewDelegate, UITableViewDataSource>:
Selector: tableView:numberOfRowsInSection:
Selector: tableView:cellForRowAtIndexPath:
Selector: numberOfSectionsInTableView:
Selector: tableView:titleForHeaderInSection:
Selector: tableView:titleForFooterInSection:
Selector: tableView:commitEditingStyle:forRowAtIndexPath:
Selector: sectionIndexTitlesForTableView:
Selector: tableView:sectionForSectionIndexTitle:atIndex:
...
...
etc.,etc.
If you want to also get the selectors for the super classes you can loop through like this:
Class c = [myObject class];
while (c != nil) {
int i = 0;
unsigned int mc = 0;
Method* mlist = class_copyMethodList(c, &mc);
NSLog(#"%d methods for %#", mc, c);
for(i = 0; i < mc; i++) {
const char* selName = sel_getName(method_getName(mlist[i]));
NSLog(#"Method #%d: %s", i, selName);
}
free(mlist);
c = [c superclass];
}