解决iPhone5等32位设备,13位时间戳转换异常

解决iPhone5等32位设备,13位时间戳转换异常_第1张图片
32-bit 64-bit

2015年初,所有提交审核的App需要适配64位,目的是充分利用ARM处理器的高性能支持,让应用能够有更为极致的体验。在iPhone5S以后的设备都是支持64位的。

一、时间显示引发的问题

解决iPhone5等32位设备,13位时间戳转换异常_第2张图片
问题页面

由于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类型

解决iPhone5等32位设备,13位时间戳转换异常_第3张图片

2、通过Dash,查看Apple官网API文档,查看NSInteger的定义如下:

构建32位应用,NSInteger32位整型
构建64位应用,NSInteger64位整型

解决iPhone5等32位设备,13位时间戳转换异常_第4张图片

注意:由于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还是longiOS编译器会自动分配完成

解决iPhone5等32位设备,13位时间戳转换异常_第5张图片

四、总结:

一个10位以上的整数。
64位系统中,使用NSInteger或者long类型,是可以正常存储的 。
32位系统中,由于字节数变了,导致溢出了。
兼容32位64位系统,使用intlong long(或者int32_tint64_t)这样的数据类型,比使用NSInteger要更加可靠,具体问题具体分析。

最后,使用了double代替NSInteger来解决该问题

参考

About 64-Bit Cocoa Touch Apps
64-bit Tips

你可能感兴趣的:(解决iPhone5等32位设备,13位时间戳转换异常)