3

I would have thought that this was an identity, but it doesn't seem to be working for me right now.

Behold my lldb prompt:

po [self class] ==> MyCustomClass

po [MyCustomClass class] ==> MyCustomClass

po [self class] == [MyCustomClass class] ==> true

p [self isKindOfClass:[MyCustomClass class]] ==> '\0' (i.e. false).

Definition of isKindOfClass: "Returns a Boolean value that indicates whether the receiver is an instance of given class or an instance of any class that inherits from that class."

What kind of nonsense (my fault or otherwise) could cause this kind of behavior?

Background for those who care: I'm unfortunately working with a 3rd-party API that needs me to pass in an object as a void pointer, then to cast it back to the proper type. Despite the fact that everything is compiling just fine, at runtime I'm being told the the object doesn't recognize the selectors I'm trying to send to it. This means (I think?) that it's not actually an instance of the class that I'm casting it to. In attempting to test it, I come across this issue with [NSObject isKindOfClass]. What on earth is going on here?

Running on an iOS 8.1 iPad, building in XCode 6.1.1.

Here's a screenshot of the last test:

lldb screenshot


PROGRESS EDIT: I finally managed to get a breakpoint into the thread this library is running on using this post, and am seeing some even crazier stuff.

given (void*)data, I get:

po [data class] ==> MyCustomClass

po [data isKindOfClass:[MyCustomClass class]] ==> nil (again, this just means false)

Obviously I've really broken something here. Are there any known issues that could cause something like this?


EDIT SSCCE-ish example: You start with a naked C function that gets passed to a background library as a callback function:

void libraryCallbackFunction(eventname, stuff, (void*)data)

The library calls this function (from a new thread) when an event occurs, and you use this function to handle the event. data is supposed to be a pointer to any old class that you want to call out to from this event handler function. Inside this function, you cast data to whatever class you want. Then, you can send messages to the data instance on the main thread. Let's call it a view controller:

void libraryCallbackFunction((void*)data) {
   MyCustomClass *myViewController = (__bridge MyCustomClass*)data;

   /* stuff stuff stuff */

   dispatch_async(dispatch_get_main_queue(), ^{
      [myViewController makeInterfaceChange];
   });
}

This snippet compiles just fine for me, but at runtime I'm getting an error:

NSInvalidArgumentException', reason: '+[MyCustomClass makeInterfaceChange]: unrecognized selector sent to class 0xf3fad8

So in other words, it appears that data doesn't actually point to an instance of MyCustomClass. Yes, makeInterfaceChange is defined for MyCustomClass, otherwise it wouldn't compile. As I've mentioned before, calling po [data class] from lldb when at a breakpoint in this function gives MyCustomClass.

Any ideas?


WAIT, COULD IT BE?: The critical (__bridge) cast in this part of the code isn't syntax highlighting, even though it is everywhere else in my project. Issue? Or just XCode being finicky with syntax highlighting, as usual? Is there any bonehead mistake that might cause __bridge to not work?

Community
  • 1
  • 1
Garrett Disco
  • 670
  • 1
  • 9
  • 27
  • To be totally correct, you should be casting the return of `isKindOfClass:` to `BOOL`: `p (BOOL)[self isKindOfClass:[MyCustomClass class]]` but that won't change the answer, just the representation you get. And don't use `po` -- that's for objects. – jscs Dec 18 '14 at 20:55
  • Garrett - Sorry my earlier answer wasn't right; thanks for clarifying. I'm going to guess that the library you are using reimplements `isKindOfClass` and breaks it. – matt Dec 18 '14 at 20:55
  • What does `isMemberOfClass:` give you? What's the library? Why does it use `void *` instead of `id`? – jscs Dec 18 '14 at 20:56
  • @matt, no worries, I wasn't terribly clear about what I was seeing anyway :). And the MyCustomClass is something I made personally, it doesn't overwrite isKindOfClass. – Garrett Disco Dec 18 '14 at 21:07
  • @Josh, I'm getting `isMemberOfClass:[MyCustomClass class]` as `NO` (using the cast you suggested). Also interesting, `isKindOfClass:[NSObject class]` is `YES`, so apparently SOMETHING valid getting passed in, just not what I think should be. – Garrett Disco Dec 18 '14 at 21:08
  • 1
    Or the class is swizzled in some way that escapes me. – matt Dec 18 '14 at 21:08
  • So you're passing an object you've created, of a class that you wrote, to an API you didn't write, via a void pointer, and it modifies the object? Or how are you getting it back? Can you post [an SSCCE](http://stackoverflow.com/help/mcve) so we can see what's going on? – jscs Dec 18 '14 at 21:16
  • if `data` is nil, the comparison will always fail. are you doing a nil check? – Nick Dec 18 '14 at 21:25
  • data is not nil. `p data` ==> `$12 = 0x00f3fad8` @JoshCaswell, working on a better description of what I'm looking at here. – Garrett Disco Dec 18 '14 at 21:26
  • If `data` was `nil`, @Nick, `[data class]` would be as well. – jscs Dec 18 '14 at 21:28
  • sorry i should have been clearer. my comment was in reference this line `[data isKindOfClass:[MyCustomClass class]]` @JoshCaswell – Nick Dec 18 '14 at 21:29
  • 2
    The `+` in the error message says that `myViewController` is a _class object_, not an instance. That explains pretty much everything. – jscs Dec 18 '14 at 22:29
  • I suspect debugger results are an artifact of the debugger. Try with NSLogs at the same point in the code. – Hot Licks Dec 18 '14 at 22:32
  • AHHHHHHHHHHHHHHHHHHHHHHHH :D :D :D :D :D :D GOT IT GOT IT. Answer to come. – Garrett Disco Dec 18 '14 at 22:34

1 Answers1

3

You're registering a class object, not an instance, to be passed to your callback. This is indicated by the + in the exception message.

The weirdness with isKindOfClass: is happening because [someClassObject class] returns itself, not its class (which would be a meta-class object). A class object, however, is not of its own kind (not a member of the class it represents); they have their own (opaque) hierarchy.

[[NSString class] isKindOfClass:[NSString class]]

e.g., produces the same result as your code: NO.

jscs
  • 63,694
  • 13
  • 151
  • 195
  • The library was started with a function like this `startLibraryInBackground(callbackFunction, dataObject, stuff)` My bonehead mistake was passing `self` as the dataObject parameter in a STATIC METHOD of my viewController class. So it was getting the class itself, not the instance. Thanks! – Garrett Disco Dec 18 '14 at 22:41
  • 1
    Glad I could help. (But remember: [they're not "static" methods in ObjC](http://stackoverflow.com/a/8089623/). :) – jscs Dec 18 '14 at 22:43