2015年初,所有提交审核的App需要适配64位,目的是充分利用ARM处理器的高性能支持,让应用能够有更为极致的体验。在iPhone5S以后的设备都是支持64位的。
一、时间显示引发的问题
由于32位处理器的NSInteger是int类型的,导致溢出,下面我们来具体看一下。
1、服务端返回JSON数据
服务端返回日期数据为13位时间戳。
{
"count": 0,
"data": {
"nowDate": 1508470153576, //13位时间戳
"skuCommission": {
"actPrice": 89,
"commissionRate": 0.1,
"endTime": 1508547599000, //13位时间戳
"isDelete": 0,
"limitCommissionRate": 0,
"limitInventory": 0,
"limitUseCoupon": false,
"skuId": 0,
"specialSell": true,
"startTime": 1508461200000, //13位时间戳
"type": 1
},
"saleInfo": {
"endTime": 1508547599000, //13位时间戳
"price": 89,
"startTime": 1508461200000 //13位时间戳
},
},
"isRedirect": 0,
"isSuccess": 1,
"login": 0
}
2、iOS客户端Model数据模型
客户端通过MJExtension(数据转模型开源库),解析为Model模型。
修改前:时间戳使用NSInteger类型
修改后:时间戳使用double类型(或者 long long类型)
@interface ProductDetailModel : NSObject
#@property (nonatomic, assign) NSInteger nowDate; //修改前
@property (nonatomic, assign) double nowDate; //修改后
@end
@interface ProductSkuCommission : NSObject
@property (nonatomic, assign) CGFloat actPrice;
@property (nonatomic, assign) CGFloat commissionRate;
#@property (nonatomic, assign) NSInteger endTime; //修改前
@property (nonatomic, assign) double endTime; //修改后
@property (nonatomic, assign) NSInteger gmtCreate;
@property (nonatomic, assign) NSInteger gmtModified;
@property (nonatomic, assign) NSInteger isDelete;
@property (nonatomic, assign) NSInteger limitCommissionRate;
@property (nonatomic, assign) NSInteger limitInventory;
@property (nonatomic, assign) NSInteger skuId;
@property (nonatomic, assign) BOOL specialSell;
#@property (nonatomic, assign) NSInteger startTime; //修改前
@property (nonatomic, assign) double startTime; //修改后
@property (nonatomic, assign) NSInteger type;
@end
@interface ProductSaleInfo : NSObject
#@property (nonatomic, assign) NSInteger endTime; //修改前
@property (nonatomic, assign) double endTime; //修改后
@property (nonatomic, assign) CGFloat price;
#@property (nonatomic, assign) NSInteger startTime; //修改前
@property (nonatomic, assign) double startTime; //修改后
@end
3、出现溢出问题
❌时间戳转换成时间后,显示异常❌,如下:
// 原始数据
1508547599000
// 64位架构,使用NSInteger
1508461200000 10月20日09点
// 32位架构,使用NSInteger
927679104 01月12日01点
二、排查问题
排查了网络返回数据,用户设备时区,使用设备机型,使用设备系统,是否越狱,转换时间方法等等,后来发现在iPhone5,iPhone5C设备中存在该问题(目前App兼容iOS8以上,暂时不考虑iPhone5以下机型),其他设备是OK的,考虑问题出在机型之间存在的差异。
1、通过XCode,按住「Command」点击「NSInteger」查看NSInteger
的定义如下:
32位CPU上,将
NSInteger
定义为了int
类型
64位CPU上,将NSInteger
定义为了long
类型
2、通过Dash,查看Apple官网API文档,查看NSInteger
的定义如下:
构建32位应用,
NSInteger
是32位整型
构建64位应用,NSInteger
是64位整型
注意:由于long和NSInteger的字节数变了,所以在兼容的时候可能会导致溢出。
相同类型在不同处理器中的差异:
类型 | 32位 处理器 | 64位 处理器 |
---|---|---|
NSInteger | int | long |
NSUInteger | unsigned int | unsigned long |
~ | ~ | ~ |
int | 32bit(4字节) | 32bit(4字节) |
long | 32bit(4字节) | 64bit(8字节) |
long long | 64bit(8字节) | 64bit(8字节) |
变量范围:
整型 | 有符号 范围 | 无符号 范围 |
---|---|---|
4字节 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 |
8字节 | -9223372036854775808 ~ 9223372036854775807 | 0 ~ 18446744073709551615 |
三、为什么用NSInteger,不直接用int或long呢?
现在,Xcode可以支持开发32位和64位的应用,为了让开发者写出在其他系统上也能够运行的代码,苹果公司引入了NSInteger类型以及NSUInteger类型。这两种类型无论在32位系统还是64位系统上都能够通用。
NSInteger以及NSUInteger类型在苹果的类库中被广泛使用,所以写Objective-C的时候,会经常使用它们。
用NSInteger 声明的整型变量,你不用关心是32位还是64位
,不用关心是声明int还是long
,iOS编译器会自动分配完成
。
四、总结:
一个10位以上的整数。
在64位系统
中,使用NSInteger
或者long
类型,是可以正常存储的 。
在32位系统
中,由于字节数变了,导致溢出了。
兼容32位
和64位
系统,使用int
, long long
(或者int32_t
,int64_t
)这样的数据类型,比使用NSInteger
要更加可靠,具体问题具体分析。
最后,使用了double代替NSInteger来解决该问题
参考
About 64-Bit Cocoa Touch Apps
64-bit Tips