64-Bit Changes To the Cocoa API
The 64-bit changes to the Cocoa API are largely targeted at those parameter and return types required for 64-bit addressing. However, consistency, ease of porting, and "impedance match" are also goals and thus most 32-bit quantities in the API are growing to 64 bits. The Cocoa 64-bit changes fall into three major categories: integers, floating-point values, and enumeration constants.
If you are a creating a new Cocoa application and you want to make it 64-bit capable from the outset, you need to incorporate the API changes into your code. You also might want to maintain a source base that ensures binary compatibility and source compatibility for both 32-bit and 64-bit architectures.
Integers
The biggest 64-bit change in the Cocoa API is the introduction of the NSInteger
and NSUInteger
data types. These two types now replace most occurrences of int
and unsigned int
in the framework headers. The parameter and return types that remain as int
and unsigned int
in Cocoa header files are unchanged for one of two reasons:
They need to be a fixed size,
They need to correspond with those defined by another API, such as file descriptors, Mach ports, and four-character codes.
On 64-bit architectures, NSInteger
and NSUInteger
are defined as long
and unsigned long
, respectively. To maintain binary compatibility with 32-bit applications, they are declared in the Foundation header file NSObjCRuntime.h
using the __LP64__
macro to distinguish between 32-bit and 64-bit builds, as follows:
#if __LP64__ |
typedef long NSInteger; |
typedef unsigned long NSUInteger; |
#else |
typedef int NSInteger; |
typedef unsigned int NSUInteger; |
#endif |
Additionally for the 64-bit initiative, many new methods have been added to the Cocoa frameworks with "integer" in their names. These methods are counterparts to other methods in the same class with "int" in their names; these methods need to continue dealing with values that are specifically int
. The "integer" methods have parameter or return types of NSInteger
or NSUInteger
while the "int" methods accept or return values of the native types int
or unsigned int
. Table 2-1 lists the new methods.
Class | Methods |
---|---|
| |
| (Note: available since OS X v10.0) |
| |
| |
| |
| |
| |
|
To set limits for the new NSInteger
and NSUInteger
types, NSObjCRuntime.h
also defines the following constants:
#define NSIntegerMax LONG_MAX |
#define NSIntegerMin LONG_MIN |
#define NSUIntegerMax ULONG_MAX |
Building 32-Bit Like 64-Bit
As shown in the previous section, Cocoa defines NSInteger
and NSUInteger
conditionally (using the __LP64__
macro) so that, as long as the project consistently uses the new data types, the underlying primitive type varies according to whether the target architecture is 32-bit or 64-bit.
The NS_BUILD_32_LIKE_64
preprocessor macro works in a different manner. It declares NSInteger
to be long
(instead of int
) and NSUInteger
to be long unsigned int
even on 32-bit portions of the source base.
#if __LP64__ || NS_BUILD_32_LIKE_64 |
typedef long NSInteger; |
typedef unsigned long NSUInteger; |
#else |
typedef int NSInteger; |
typedef unsigned int NSUInteger; |
#endif |
This makes it possible to do something like the following without getting warnings.
NSInteger i; |
printf("%ld", i); |
The NS_BUILD_32_LIKE_64
macro is useful when binary compatibility is not a concern, such as when building an application.
Floating-Point Values
Floating point quantities in the Core Graphics framework (Quartz), which are float
on 32-bit architectures, are being expanded to double
to provide a wider range and accuracy for graphical quantities. Core Graphics declares a new type for floating-point quantities, CGFloat
, and declares it conditionally for both 32-bit and 64-bit. This change affects Cocoa because of its close dependency on Core Graphics. Where a parameter or return value in the Cocoa frameworks is a graphical quantity, CGFloat
now replaces float
.
The CGFloat
changes made in the Foundation and, especially, the Application Kit are so numerous that its easier to point out the methods with floating-point parameters and return types that don't change to CGFloat
; that is, they remain as float
. These methods fall into certain categories, described in the captions to Table 2-2, Table 2-3, Table 2-4, Table 2-5, and Table 2-6.
Class | Methods |
---|---|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| About a dozen "swap" functions. |
Class | Methods |
---|---|
| |
| |
| |
|
Class | Methods |
---|---|
|
|
|
|
|
|
Class | Methods |
---|---|
|
|
|
|
Class | Methods |
---|---|
|
|
Enumeration Constants
A problem with enumeration (enum
) constants is that their data types are frequently indeterminate. In other words, enum
constants are not predictably unsigned int
. With conventionally constructed enumerations, the compiler actually sets the underlying type based on what it finds. The underlying type can be (signed) int
or even long
. Take the following example:
type enum { |
MyFlagError = -1, |
MyFlagLow = 0, |
MyFlagMiddle = 1, |
MyFlagHigh = 2 |
} MyFlagType; |
The compiler looks at this declaration and, finding a negative value assigned to one of the member constants, declares the underlying type of the enumeration int
. If the range of values for the members does not fit into an int
or unsigned int,
then the base type silently becomes 64-bit (long
). The base type of quantities defined as enumerations can thus change silently size to accord with the values in the enumeration. This can happen whether you're compiling 32-bit or 64-bit. Needless to say, this situation presents obstacles for binary compatibility.
As a remedy for this problem, Apple has decided to be more explicit about the enumeration type in the Cocoa API. Instead of declaring arguments in terms of the enumeration, the header files now separately declare a type for the enumeration whose size can be specified. The members of the enumeration and their values are declared and assigned as before. For example, instead of this:
typedef enum { |
NSNullCellType = 0, |
NSTextCellType = 1, |
NSImageCellType = 2 |
} NSCellType; |
there is now this:
enum { |
NSNullCellType = 0, |
NSTextCellType = 1, |
NSImageCellType = 2 |
}; |
typedef NSUInteger NSCellType; |
The enumeration type is defined in terms of NSInteger
or NSUInteger
to make the base enumeration type 64-bit capable on 64-bit architectures. For OS X v10.5 all enumerations declared in the Cocoa frameworks now take this form. In some cases, an enumeration type is now declared where one had not existed before.
Unfortunately, this change affects type checking of enumeration constants; you can pass any integer value in a method parameter typed as, say, NSCellType
, not just one of the values in the enumeration. However, the change does allow more specific typing of bit masks, which were previously declared as unsigned int
. You can now use the typedef
s for parameters which are bit masks. For instance,
- (NSComparisonResult)compare:(NSString *)string options:(unsigned)mask; |
can now be
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask; |
Other Related Changes (and Non-Changes)
The use of some of the other primitive C types in the Cocoa API are changing in the 64-bit initiative, while others are unaffected. The following summarizes the changes and non-changes:
char
andshort
— No changes in the Cocoa API.long
— In versions of OS X prior to version 10.5, the scripting and Apple event part of the Cocoa API usedlong
for four-byte codes; these return types and parameter types are now changing toFourCharCode
.long long
— Prior to OS X v10.5, theNSFileHandle
class usedlong long
for file offsets, which gives a 64-bit value on both 32-bit and 64-bit architectures. This is unchanged.
The Cocoa OpenGL API (including the classes NSOpenGLContext
, NSOpenGLPixelBuffer
, NSOpenGLPixelFormat
, and NSOpenGLView
) follow the data-type changes made for the C OpenGL framework for Leopard by adopting the standard OpenGL types such as GLint
, GLsizei
, and GLenum
for parameters and return values. These types were chosen in part to maintain binary compatibility under 32-bit (where long
and int
are the same size).
The Objective-C runtime API (/usr/include/objc
) has undergone significant modification for OS X v10.5. Most Cocoa developers don't directly call these functions, so these changes should not affect them. However, if you do use the Objective-C runtime API, you should be aware that there are implications for 64-bit binaries. If you are building your project 64-bit, you cannot use the old Objective-C runtime API.
Copyright © 2013 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2013-09-17