Besides the technical discussions above, I think the answer is related to the history of the language and its preference for conventions over syntax. Formal protocols weren't originally part of the language — everything was informal. Apple have subsequently mostly shifted to formal protocols, but informal protocols are part of the language and are used by parts of the official API. They are therefore a fully supported, first class part of Objective-C.
If you look at the documentation to NSArray
, it says, amongst other things:
In most cases your custom NSArray class should conform to Cocoa’s
object-ownership conventions. Thus you must send retain to each object
that you add to your collection and release to each object that you
remove from the collection. Of course, if the reason for subclassing
NSArray is to implement object-retention behavior different from the
norm (for example, a non-retaining array), then you can ignore this
requirement.
And:
NSArray is “toll-free bridged” with its Core Foundation counterpart,
CFArray [...] you can sometimes do things with CFArray that you cannot easily do with NSArray. For example, CFArray provides a set of callbacks, some of which are for implementing custom retain-release behavior. If you specify NULL implementations for these callbacks, you can easily get a non-retaining array.
Your question therefore rests on a false premise, specifically either a partial reading of the documentation or an incomplete consideration of the language.
id <NSObject>
is correctly not used because the NSObject
protocol doesn't match the protocol that objects must implement to be usable with NSArray
. Instead an informal protocol, that happens to be a subset of NSObject
, is established in the documentation (albeit at a second remove of informality, which is rare). Although informal protocols are increasingly uncommon, they're valid and not yet exceptional.
So, the short version of my answer is: NSArray
documents an informal protocol, that protocol isn't the same as NSObject
. Informal protocols aren't represented in syntax, hence id
.