32-bit 64-bit
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; //修改后
@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;
@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; //修改后
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来解决该问题
..UNIX时间戳是一种表示时间的方法,广泛用于计算机系统和网络协议中。它定义的时间起点是1970年1月1日午夜(协调世界时UTC),也就是所谓的“UNIX纪元”开始的时刻。
将 13 位整数的毫秒时间戳转化成本地普通时间 (datetime格式)将 10 位整数的秒级时间戳转化成本地普通时间 (datetime格式)将 13 位整数的毫秒级时间戳转化成 本地普通时间 (字符串格式)将 10 位整数的秒级时间戳转化成 本地普通时间 (字符串格式)
var year = aa.getFullYear();
var month = (aa.getMonth() + 1) < 10 ? "0" + (aa.getMonth() + 1) : "";
var day = (aa.getDay()) < 10 ? "0" + (aa.getDay()) : "";
var endTime = year + "-" + month + "-" + day;
console.log
在32位的机子上,time_t是个4字节的值,存储的是1900年到现在的秒数,最大可存放的秒数(时间戳)到2038年多,设置的tm_year不能超过138,多了会溢出,返回异常值。
解决方法:
修改mktime函数的返回值类型
unsigned long -> unsigned long long
unsigned long long my_mktime(const unsigned int year0, const unsigned int mon0,
const unsign