苹果在2014年10月20号发布了一条消息:从明年的二月一号开始,提交到App Store的应用必须支持64-bit。详细消息地址为:https://developer.apple.com/news/?id=10202014a

那们我们应该如何开始着手让自己的App支持64-Bit呢?

基本知识

从iPhone 5S的A7 CPU开始到刚刚发布的iPhone 6(A8 CPU)都已经支持64-bit ARM 架构。关于64-bit的介绍详见维基百科。知乎上有很多关于苹果使用A7,A8芯片的讨论,可以参考 iPhone 6 的 Apple A8 芯片对比 Apple A7 提升明显吗?, iPhone 5s 配备的 A7 处理器是 64 位,意味着什么

  • 1.Xcode 5.0.1开始支持编译32-bit和64-bit的Binary

  • 2.同时支持32-bit和64-bit,我们需要选择的minimum deployment target为 iOS 5.1.1

  • 3.64-bit的Binary必须运行在支持64-bit的CPU上,并且最小的OS版本要求是 7.0.3

关于Xcode “Build Setting”中的Architectures参数问题

  • 1.Architectures:你想支持的指令集。(支持指令集是通过编译生成对应的二进制数据包实现的,如果支持的指令集数目有多个,就会编译出包含多个指令集代码的数据包,造成最终编译的包很大。)

  • 2.Valid architectures:即将编译的指令集。(Valid architectures 和 Architecture两个集合的交集为最终编译生成的版本)

  • 3.Build Active Architecture Only:是否只编译当前设备适用的指令集(如果这个参数设为YES,使用iPhone 6调试,那么最终生成的一个支持ARM64指令集的Binary。一般在DEBUG模式下设为YES,RELEASE设为NO)

关于指令集如下参考:

ARMv8/ARM64: iPhone 6(Plus), iPhone 5s, iPad Air(2), Retina iPad Mini(2,3)

ARMv7s: iPhone 5, iPhone 5c, iPad 4

ARMv7: iPhone 3GS, iPhone 4, iPhone 4S, iPod 3G/4G/5G, iPad, iPad 2, iPad 3, iPad Mini

ARMv6: iPhone, iPhone 3G, iPod 1G/2G

对于支持64-bit,我们可以设置Architectures为 Standard architectures,在最新的Xcode 6上,它包括 armv7和arm64。

让App支持32-bit和64-bit基本步骤

1.确保Xcode版本号>=5.0.1

2.更新project settings, minimum deployment target >= 5.1.1

3.改变Architectures为 Standard architectures(include 64-bit)

4.运行测试代码,解决编译warnings and errors,对照本文档或者官方文档 64-Bit Transition Guide for Cocoa Touch对相应地方做出修改。(编译器不能告诉我们一切)

5.在真实的64-bit机器上测试。

6.使用Instruments查看内存使用问题。

64-bit主要的变化

64-bit运行时环境和32-bit运行时环境主要有以下两点的不同:

数据类型的改变

方法调用上的改变

数据类型的改变

整型数据类型的变化如下:

关于字节对齐的概念可以参考如下链接:C语言字节对齐

浮点型类型的改变如下:

数据类型的改变可能会为我们的程序带来这些影响:

1.增加内存压力

2.64-bit到32-bit数据之间的相互转化

3.计算可能产生不同的结果

4.当把一个值从大的数据类型拷贝到小的数据类型,数据可能被截断。(NSInteger -> int)

方法调用上的改变

基于32-bit的CPU和基于64-bit上的CPU有不同数量的寄存器,在方法调用上有不同的协议。因此32-bit和64-bit在汇编层级上是不同的。如果我们在程序中不使用汇编编程,调用协议很少会遇到。

如何编写健壮的64-bit代码

根据上述改变,官方文档 64-Bit Transition Guide for Cocoa Touch给出如下7步:

1.不要将长整型long赋值给整型int (64-bit上会导致数据丢失)

2.不要将指针类型pointer赋值给整型int (64-bit导致地址数据丢失)

3.留意数值计算(掩码计算,无符号整数和有符号整数同时使用等)

4.留意对齐方法带来的变化

5.32-bit到64-bit之间数据转化(通过网络传递的用户数据,可能同时存在于32-bit和64-bit的环境下)

6.重写汇编代码

7.不要在可变参数方法和不可变参数方法之前进行强制转化

在LLVM编译器中,枚举类型也可以定义枚举的大小。我们在使用中,指派枚举值到一个变量时,应该使用适当的数据类型。

不要将指针类型pointer赋值给整型int

1
2
3
4
5
6
7
8
int a = 5;
int *c = &a;
 
/* 32-bit下正常,64-bit下错误。最新的Xcode6.0编译提示警告:'Cast to int* for smaller integer type int'*/
int *d = (int *)((int)c + 4); 
 
/* 正确, 指针可以直接增加*/
int *d = c + 1;

如果我们一定要把指针转化为整型,可以把上述代码改为:

1
2
/* 32-bit和64-bit都正常。*/
int *d = (int *)((uintptr_t)c + 4);

查看uintptr_t定义为 typedef unsigned long uintptr_t;

保持数据类型一致

方法使用时,入参,出参和赋值都需要注意保持数据类型一致。在iOS App中尤其要注意以下几个类型的正确使用:

  • long

  • NSInteger

  • CFIndex

  • size_t

在32-bit和64-bit下,fpos_t和off_t都是64 bits的数据大小,永远不要把它们指向int整型。

1
2
3
4
5
6
7
8
9
10
11
12
13
long PerformCalculation(void);
int c = PerformCalculation(); // 错误 64-bit上数据将被截取
long y = PerformCalculation(); // 正确
 
 
int PerformAnotherCalculation(int input);
long i = LONG_MAX;
int x = PerformCalculation(i); // 错误
 
int ReturnMax()
{
    return LONG_MAX; // 错误
}

Cocoa中常见的数据类型转化问题

NSInteger : 在32-bit和64-bit下有分别的定义:

1
2
3
4
5
    #if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
        typedef long NSInteger;
    #else
        typedef int NSInteger;
    #endif

我们永远不应该假设NSInteger和int是一样大的,下面的例子在使用中就需要注意:

1.使用NSNumber对象转化时

2.使用NSCoder编解码的时候,如果在64-bit设备下对NSInteger编码,在32-bit设备下对NSInteger解码。解码时如果值的大小超过了32-bit,这个时候就会出现异常

3.Famework中使用NSInteger定义的一些常量

CGFloat: 和NSInteger一样有不同的定义

1
2
3
4
5
6
7
typedef CGFLOAT_TYPE CGFloat;
 
#if defined(__LP64__) && __LP64__
# define CGFLOAT_TYPE double
#else
# define CGFLOAT_TYPE float
#endif

下面给出错误示范:

1
2
3
4
5
CGFloat value = 200.0;
CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &value); //64-bit下出现错误
 
CGFloat value = 200.0;
CFNumberCreate(kCFAllocatorDefault, kCFNumberCGFloatType, &value); //正确

整型数值计算问题

关于C语言的符号位扩展可参考资料为:符号位扩展

我们直接来看例子:

1
2
3
4
5
6
7
8
9
    int a = -2;
 
    unsigned int b = 1;
 
    long c = a + b;
 
    long long d = c;
 
    printf("%lld\n", d);

问题:这段代码在32-bit下运行结果符合我们的预期,输出为 -1(0xffffffff)。在64-bit下运行结果为:4294967295 (0x00000000ffffffff)。

原因:一个有符号的值和一个同样精度的无符号的值相加结果是无符号的。这个无符号的结果被转换到更高精度的数值上时采用零扩展。

解决方案:把变量b换成长整型long

创建数据结构时使用合适的数据大小

C99提供了内置的数据类型保证了一致的数据大小,即使底层的硬件结构不同。在某些case下,我们知道数据是一个固定的大小或者一个特定的变量拥有一个有限的取值范围。这个时候,我们应该选择特定的类型以避免浪费内存。

类型如下:

永远不要使用malloc去为变量申请特定内存的大小,改为使用sizeof来获取变量或者结构体的大小。

另外我们还需要注意修改格式化字符串来同时支持32-bit和64-bit。

小心处理方法和方法指针

1
2
3
4
5
6
7
8
int fixedFunction(int a, int b);
int variadicFunction(int a, ...);
 
int main
{
    int value2 = fixedFunction(5,5);
    int value1 = variadicFunction(5,5);
}

上述两个方法中,在32-bit下使用相同的指令读取参数的数据,但是在64-bit上,是使用完全不同的协议来编译的。

如果在代码中传递方法指针,应该保证方法调用的协议是一致的。永远不要将一个可变参数的方法转化成固定参数的方法。

1
2
3
4
int MyFunction(int a, int b, ...);
 
int (*action)(int, int, int) = (int (*)(int, int, int)) MyFunction;
action(1,2,3); // 错误示范

上述错误的写法,编译器是不会提示警告或者错误的,并且在模拟器中也不会暴露出问题来。在发布自己的App前,一定记得要使用真机去测试。

总结

在支持64-bit过程中,应该按照Apple文档中提供的7个步骤完整检查项目工程。如果工程中涉及到大量的C或者C++代码,在支持64-bit中要更加谨慎。

写完这篇笔记后,我觉得需要重温一下C的基础知识。XD,顺便祈祷项目中的第三方库赶紧更新支持64-bit,阿弥陀佛。

ps: 找出不支持arm64的静态库 find . -name *.a -exec lipo -info "{}" \;

iOS工程如何支持64-bit的更多相关文章

  1. Unity3d使用高通Vuforia发布IOS工程不支持64位的一些解决办法

    1.将Unit升级至4.6.x或5.0.x,将Vuforia差距升级到最新版本(vuforia-unity-mobile-android-ios-4-0-105 ) 2.平台Other Setting ...

  2. iOS工程如何支持64-bit(转)

    苹果在2014年10月20号发布了一条消息:从明年的二月一号开始,提交到App Store的应用必须支持64-bit.详细消息地址为:https://developer.apple.com/news/ ...

  3. IOS 工程所支持的版本 设置

    如何设置 Base SDK 和 iOS Deployment Target ? http://leopard168.blog.163.com/blog/static/16847184420116159 ...

  4. cocos2d-x v2.2 IOS工程支持64-bit 遇坑记录

    修改缘由 由于 iPhone 5S的A7 CPU   iPhone 6(A8 CPU)都已经支持64-bit ARM 架构,据说64位处理器跑64代码会提高处理能力?因此二月一新提交appstore应 ...

  5. iOS工程适配64-bit经验分享

    终究还是来了.Apple下发了支持64位的最后通牒: As we announced in October, beginning February 1, 2015 new iOS apps submi ...

  6. GJM : Unity3D HIAR -【 快速入门 】 六、导出 iOS 工程

    导出 iOS 工程 在开始之前,请务必先保存您的工程.由于 Unity 无法直接生成 ipa 文件,您需要先导出 iOS 工程文件,然后通过 Xcode 编译生成. Step 1. 选择平台 在 Un ...

  7. iOS 工程自动化 - 思路整理

    4 月份参加 2017@Swift 大会的时候有幸听到了 @zesming 大佬关于美团组件化的 Topic,有一张图印象特别深刻. 来自 @zesming 大佬 后来跟 @zesming 大佬沟通怎 ...

  8. 如何将 iOS 工程打包速度提升十倍以上

    如何将 iOS 工程打包速度提升十倍以上   过慢的编译速度有非常明显的副作用.一方面,程序员在等待打包的过程中可能会分心,比如刷刷朋友圈,看条新闻等等.这种认知上下文的切换会带来很多隐形的时间浪费. ...

  9. iOS 工程自动化 - OCLint

    前言 最近一直在做 iOS 工程自动化方向的事情,所以把自己研究和实践的内容进行记录并分享,希望能给大家一些帮助. 为什么要使用 OCLint 做为一个静态代码分析工具,我们引入 OCLint 的目的 ...

随机推荐

  1. 解决javax.imageio.IIOException: Can't create output stream!

    解决javax.imageio.IIOException: Can't create output stream! javax.imageio.ImageIO.write(image, "J ...

  2. jquery判断是否出现滚动条

    $(document).ready(function(){ var winH = $(window).height(); //页面可视区域高度 $(window).scroll(function () ...

  3. 常用NuGet插件

    1.Install-Package System.Data.SQLite 2.Install-Package FluentData

  4. SQL - 分页存储过程

    http://www.jb51.net/article/71193.htm http://www.webdiyer.com/utils/spgenerator/ create PROCEDURE [d ...

  5. mysql时该如何估算内存的消耗,公式如何计算?

    经常有人问配置mysql时该如何估算内存的消耗.那么该使用什么公式来计算呢? 关心内存怎么使用的原因是可以理解的.如果配置mysql服务器使用太少的内存会导致性能不是最优的;如果配置了太多的内存则会导 ...

  6. Samba结合AD实现域帐号认证的文件服务器

    准备一台Windows域控制器, 在Samba服务器上安装Webmin图形化管理工具, samba, krb5-user, winbind. 修改/etc/krb5.conf. [logging] d ...

  7. 随机(Random)

    随机(Random)随机是智能的基础,人工智能的很多技术都需要用到随机,因此有必要把这个提到前面谈谈一考虑基于C/C++,般我们都是使用的rand ()等函数实现随机,当然我们也有吊炸天的boost库 ...

  8. PHP学习(五)----jQuery和JSON数据

    对于jQuery: jQuery 是一个 JavaScript 库. jQuery 极大地简化了 JavaScript 编程.

  9. Swapping

    COMPUTER ORGANIZATION AND ARCHITECTURE DESIGNING FOR PERFORMANCE NINTH EDITION Referring back to Fig ...

  10. arcgis server site 快速恢复与重建

    背景 在实际的工作中,会遇到如下的情形: arcgis server服务能够启动,但是由于未知的操作原因导致site里面的某个功能出现故障. 要想在短时间内,使得server能够恢复正常功能.且: 不 ...