My best answer is that it's easier to market, especially since it exacerbates the difference between different versions. It only really works for products where the newer version is always better/improved over the previous version, and generally only where the product stands alone/doesn't have substantially different variations (e.g. Windows XP, which had totally separate releases for desktops, media centres and tablet PCs).
In the early releases of MacOS and Mac OS X, Apple didn't use the project codenames publicly. When Apple acquired NeXT and started working on a Unix-based MacOS, they began using codenames like "Yellow Box", "Blue Box", "Red Box" and "Rhapsody". That seemed to have been a deliberate decision to break from the purely numerical OS versions that had preceded it (System 6, System 7, System 7.5, MacOS 8, MacOS 8.1, MacOS 8.5, MacOS 9, MacOS 9.1, MacOS 9.2), and probably to hedge their bets a little bit after what had happened with Copland.
Once Mac OS X was released to the public, it was branded simply "Mac OS X" (at least after the Public Beta period). The codenames for the first two commercial releases of Mac OS X (Cheetah and Puma) were not used anywhere in their marketing. It wasn't until Mac OS X 10.2 (Jaguar) that Apple started to really use the codename in their marketing. While I don't have any real proof of the reasoning, as a user it made sense to me; Jaguar was the first Mac OS X release that many people felt was mature enough to migrate to from MacOS 9. It was fast, pretty and substantially more stable than its predecessor. It seemed Apple had really begun telling people about Jaguar by name since it let them reduce confusion (while only Puma was commercially available). By calling Puma "10.1" and Jaguar by its name, the two products where more easily distinguished.
Ask yourself; if you're running Mac OS X v10.3 and Apple releases v10.4, do you feel compelled to upgrade? That's not even a full number! Compare "Panther" to "Tiger", though, and it's easier for laypeople to distinguish.
There are other advantages too: as a software vendor you can give "names" to any release you like, and skip others. That allows you to present minor releases as major ones to the public. Look at Android's naming scheme:
- Android beta (no name)
- Android 1.0 (no name)
- Android 1.1 (no public name; called "Petit Four" internally)
- Android 1.5 (Cupcake)
- Android 1.6 (Donut)
- Android 2.0/2.1 (Eclair)
- Android 2.2 (Froyo)
- Android 2.3 (Gingerbread)
- Android 3 (Honeycomb)
- Android 4.0 (Ice Cream Sandwich)
- Android 4.1/4.2 (Jelly Bean)
By using names instead of numerals, Google has been able to bundle multiple point releases under one title (e.g. Eclair and Jelly Bean), and while some names like Gingerbread represented only a minor release over its predecessor, other names like Honeycomb or Ice Cream Sandwich represented full major releases. That flexibility is very useful for marketing.
It's worth mentioning that Windows has recently returned to using version numbers in their release names after a period of not doing so (2000, XP, Vista), but have only ever used their codename in one public release (Millennium; which became Windows Millennium Edition or Windows Me). The codenames, for other those other releases, incidentally, were Janus, Whistler and Longhorn.
One explanation for why they might choose not to use the project's codename is that it allows releases to share one brand even if the internal project teams were given vastly different names (e.g. Windows XP has 7 versions released under the "Windows XP" masthead, but their internal codenames were "Whistler", "Mantis", "Freestyle", "Harmony", "Symphony", "Emerald", and "Lonestar"). Those names also don't communicate any meaningful difference between versions, which makes them very difficult to communicate to customers.