在 Objective-C 中,数字处理主要分为两类:基本 C 语言类型(如 int, float)和对象类型(如 NSNumber, NSDecimalNumber)。
由于 Objective-C 的集合类(如 NSArray, NSDictionary)只能存储对象,不能直接存储基本类型,因此掌握如何将数字“对象化”是开发的关键。
1. 核心概念:基本类型 vs 对象类型
| 类型 | 例子 | 存储位置 | 集合支持 |
|---|---|---|---|
| 基本类型 (Scalar) | int, double, BOOL, NSInteger | 栈内存 | 不支持直接存入数组/字典 |
| 对象类型 (Object) | NSNumber, NSDecimalNumber | 堆内存 | 完美支持 |
2. NSNumber:最常用的数字包装器
NSNumber 可以包装所有的标准 C 语言数字类型。
快速语法(语法糖)
现代 Objective-C 推荐使用 @ 符号快速创建对象:
NSNumber *intObj = @10; // 整数
NSNumber *floatObj = @3.14f; // 浮点数
NSNumber *doubleObj = @3.14159; // 双精度
NSNumber *boolObj = @YES; // 布尔值
NSNumber *charObj = @'A'; // 字符
3. 学习代码案例
下面的代码展示了如何创建数字对象、在数组中使用它们,以及如何转回基本类型。
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 1. 创建 NSNumber 对象 (使用字面量语法)
NSNumber *myInt = @42;
NSNumber *myDouble = @3.14159;
NSNumber *myBool = @YES;
// 2. 将对象放入数组 (基本类型 int 做不到这一点)
NSArray *numberArray = @[myInt, myDouble, myBool];
NSLog(@"数组内容: %@", numberArray);
// 3. 从对象中提取基本类型 (Unboxing)
int i = [myInt intValue];
double d = [myDouble doubleValue];
BOOL b = [myBool boolValue];
NSLog(@"还原后的值: %d, %f, %d", i, d, b);
// 4. 数字比较
NSNumber *numA = @100;
NSNumber *numB = @200;
if ([numA compare:numB] == NSOrderedAscending) {
NSLog(@"numA 小于 numB");
}
// 5. 判断相等
if ([numA isEqualToNumber:@100]) {
NSLog(@"值相等");
}
}
return 0;
}
4. NSDecimalNumber:高精度计算(金融必备)
如果你在开发电商或金融应用,绝对不能用 float 或 double,因为它们存在浮点数精度丢失问题。此时要用 NSDecimalNumber。
// 计算 0.1 + 0.2
NSDecimalNumber *num1 = [NSDecimalNumber decimalNumberWithString:@"0.1"];
NSDecimalNumber *num2 = [NSDecimalNumber decimalNumberWithString:@"0.2"];
// 加法运算
NSDecimalNumber *sum = [num1 decimalNumberByAdding:num2];
NSLog(@"精确计算结果: %@", sum); // 输出 0.3,而不会是 0.300000000004
5. NSValue:包装结构体
NSNumber 是 NSValue 的子类。NSValue 可以包装更复杂的 C 结构体(如坐标、范围)。
// 包装常见的 UIKit/CoreGraphics 结构体 (iOS 开发常用)
// CGPoint p = {10, 20};
// NSValue *pointValue = [NSValue valueWithCGPoint:p];
// 通用包装 (自定义结构体)
typedef struct { int rank; int score; } PlayerStats;
PlayerStats s = {1, 100};
NSValue *statValue = [NSValue valueWithBytes:&s objCType:@encode(PlayerStats)];
6. 开发者避坑指南(重点)
- 不要用
==比较NSNumber对象:numA == numB比较的是内存地址。- 必须使用
[numA isEqualToNumber:numB]或compare:。
- NSInteger 不是对象:
NSInteger只是int或long的别名。它依然是基本类型。只有NSNumber才是对象。
- 不可变性:
NSNumber对象一旦创建,值就不能更改。如果需要改变,必须创建一个新的对象。
总结:学习路径
- 初学者:先掌握
@10这种写法,学会如何把数字存进NSArray。 - 进阶:理解
intValue,doubleValue等转换方法。 - 实战:在涉及钱的计算时,强制自己使用
NSDecimalNumber。