>> Is there ever a case in AppKit where a user interface item would not inherit from NSObject?
There used to be, although this case probably doesn't exist any more, except possibly in very old legacy code. There used to be two root classes: NSObject and NSProxy. The latter was used for some distributed object functionality, but that's basically fallen by the wayside. However, that's why NSObject exists as a protocol at all — it was broken off from the NSObject class as the set of behaviors that local proxies for remote objects needed to implement locally.
Over the years, there has been a small amount of variation in the SDKs whether protocols conformed to NSObject, or didn't but were used as "NSObject<protocol-name>*", or didn't but were used as "id<protocol-name>". These things are all technically distinct, but practically interchangeable.
Life is too short to expend much energy on this, beyond noticing the apparent inconsistencies and moving on. Note that your code would be slightly more correct like this:
if ([(id)item isKindOfClass:[NSMenuItem class]])
In theory again, casting it to "NSObject*" is lying to the compiler, since you don't "know" that it's an object of that class, while it's always legal to try to send a known message to anything of type "id". In practice, it's the same, because the Obj-C compiler doesn't do any optimization based on the class.
One final nit for the picking: It looks like casting to "id" ought to be unnecessary, because "item" looks like it's already typed to "id". However, in the current Obj-C language, the special compile-time behavior that allows you to send any known message (regardless of what class it's known in) to an "id" receiver isn't available for type "id<protocol-name>".