2

My colleague and I are building an async data layer heavily based on PromiseKit v1.5.3. We've noticed in certain circumstances, when returning a promise (call it X) from a block passed to then, the next then block actually passes Promse X as the argument to the block, rather than what the former promise actually resolved to. Chaining thenable promises is a pretty important feature for most Promise implementations, so we were pretty surprised.

After some pretty lengthy debug sessions, we've found the problem to be within PromiseKit. During the resolution process, an IsPromise call fails to identify the object as a promise, which is really a simple call to

[result isKindOfClass:[PMKPromise class]]

This call returns nil, and an incorrect branch is executed. Here's the source

The baffling thing about this, is that I don't see any reason for this to happen. I don't think this is a bug in PromiseKit since their code appears to be sound. I've confirmed the underlying object is indeed a PMKPromise since it responds to promise methods such as value and fulfilled. I've even pushed it through the correct branch using the debugger and it executes correctly from there!

Here's an interesting log from some tests while halted at the given line.

Given that isKindOfClass is returning nil, it sounds like that object isn't responding to the message... but it's certainly an NSObject. I'm curious if this may be a weird compiler setting or something. I currently have my optimizations set to none if that's relevant. Has anyone ever seen anything like this or know what's going on? What should I check?

eriknelson
  • 849
  • 2
  • 11
  • 21
  • 1
    `isKindOfClass` returns a BOOL. Kind of hard to tell from a `nil` in the best case, and if you pass a `nil` to `isKindOfClass` it gets even harder. – Hot Licks May 23 '15 at 22:54
  • BTW, `po` means "print object". – Hot Licks May 23 '15 at 23:01
  • Happy to add to the question if downvoters could voice their complaint? – eriknelson May 23 '15 at 23:16
  • 1
    `isKindOfClass` is *not* returning `nil`. It couldn't if it wanted to. – Hot Licks May 23 '15 at 23:19
  • Try `po NO` in the console. – Hot Licks May 23 '15 at 23:20
  • Color me corrected. Regardless, it's returning NO and falling through the wrong branch. Any ideas why? – eriknelson May 23 '15 at 23:21
  • Dial your blood pressure down a few points and go back through it again. Probably you're missing something obvious. But what Gnasher suggests is a possibility, when you're using a package like this. – Hot Licks May 23 '15 at 23:27
  • `isKindOfClass` *could* return `nil`... but the only way for it to do that is if the message is being passed to `nil`. Any time you send a message to `nil` in Objective-C, it returns `nil`. – nhgrif May 24 '15 at 12:32
  • PromiseKit author. I'll happily help if you could show the chain that causes this? Is it repeatable? Indeed, doesn’t sound like a PromiseKit bug precisely but I'd feel better if we could prove it and identify the problem. If you can provide the chain, maybe open a ticket at GitHub as that would be a better forum IMO. – mxcl May 24 '15 at 18:21
  • FYI po is saying `nil` for `NO` because it always tries to interpret its input as an object, and in object land, `0` is `nil`, not `NO`. – mxcl May 24 '15 at 18:22
  • See also http://stackoverflow.com/questions/5755289/iskindofclass-returns-false-negative-in-unit-test-bundle – iwasrobbed Oct 30 '15 at 13:51

1 Answers1

3

isKindOfClass returns unexpected results when you manage to have the same class twice in your project. So you may have an object of class PMKPromise, but it is a different class (with exactly the same class name, exactly the same behaviour, just a second class). Maybe that's what happens. Obviously setting a breakpoint and checking what the object is would help.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • This was exactly the issue. Examined the symbol tables and our cocoapods lib was getting linked into the test target as well as the app target. Reorganized our Podfile to use the `exclusive` flag on the test target and that did the trick. Thanks! – eriknelson May 25 '15 at 15:30