ios7适配一些问题(http://www.cocoachina.com/ios/20130703/6526.html)
http://www.codeceo.com/article/ios-64-bit.html
苹果在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 位,意味着什么?
- Xcode 5.0.1开始支持编译32-bit和64-bit的Binary
- 同时支持32-bit和64-bit,我们需要选择的minimum deployment target为 iOS 5.1.1
- 64-bit的Binary必须运行在支持64-bit的CPU上,并且最小的OS版本要求是 7.0.3
关于Xcode “Build Setting”中的Architectures参数问题
- Architectures:你想支持的指令集。(支持指令集是通过编译生成对应的二进制数据包实现的,如果支持的指令集数目有多个,就会编译出包含多个指令集代码的数据包,造成最终编译的包很大。)
- Valid architectures:即将编译的指令集。(Valid architectures 和 Architecture两个集合的交集为最终编译生成的版本)
- 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基本步骤
- 确保Xcode版本号>=5.0.1
- 更新project settings, minimum deployment target >= 5.1.1
- 改变Architectures为 Standard architectures(include 64-bit)
- 运行测试代码,解决编译warnings and errors,对照本文档或者官方文档 64-Bit Transition Guide for Cocoa Touch对相应地方做出修改。(编译器不能告诉我们一切)
- 在真实的64-bit机器上测试
- 使用Instruments查看内存使用问题
64-bit主要的变化
64-bit运行时环境和32-bit运行时环境主要有以下两点的不同:
- 数据类型的改变
- 方法调用上的改变
数据类型的改变
整型数据类型的变化如下:
关于字节对齐的概念可以参考如下链接:http://blog.csdn.net/21aspnet/article/details/6729724#comments
浮点型类型的改变如下:
数据类型的改变可能会为我们的程序带来这些影响:
- 增加内存压力
- 64-bit到32-bit数据之间的相互转化
- 计算可能产生不同的结果
- 当把一个值从大的数据类型拷贝到小的数据类型,数据可能被截断。(NSInteger -> int)
方法调用上的改变
基于32-bit的CPU和基于64-bit上的CPU有不同数量的寄存器,在方法调用上有不同的协议。因此32-bit和64-bit在汇编层级上是不同的。如果我们在程序中不使用汇编编程,调用协议很少会遇到。
如何编写健壮的64-bit代码
根据上述改变,官方文档 64-Bit Transition Guide for Cocoa Touch给出如下7步:
- 不要将长整型long赋值给整型int (64-bit上会导致数据丢失)
- 不要将指针类型pointer赋值给整型int (64-bit导致地址数据丢失)
- 留意数值计算(掩码计算,无符号整数和有符号整数同时使用等)
- 留意对齐方法带来的变化
- 32-bit到64-bit之间数据转化(通过网络传递的用户数据,可能同时存在于32-bit和64-bit的环境下)
- 重写汇编代码
- 不要在可变参数方法和不可变参数方法之前进行强制转化
在LLVM编译器中,枚举类型也可以定义枚举的大小。我们在使用中,指派枚举值到一个变量时,应该使用适当的数据类型。
创建数据结构时使用合适的数据大小
C99提供了内置的数据类型保证了一致的数据大小,即使底层的硬件结构不同。在某些case下,我们知道数据是一个固定的大小或者一个特定的变量拥有一个有限的取值范围。这个时候,我们应该选择特定的类型以避免浪费内存。
类型如下:
永远不要使用malloc去为变量申请特定内存的大小,改为使用sizeof来获取变量或者结构体的大小。
另外我们还需要注意修改格式化字符串来同时支持32-bit和64-bit。
1. 如何判断版本
如果你已经开发过ios旧版本的app,现在想适配在ios7上,那如何判断现在的版本类型是一个很有用的办法:
[[[UIDevice currentDevice] systemVersion] floatValue] < 7.0 //如果当前ios版本小于7
2. edgesForExtendedLayout //视图控制器,四条边不指定
在上述代码中,我们没有设置edgesForExtendedLayout的值,所以默认就是UIRectEdgeAll,viewController的view的布局延伸到了整个屏幕(可以看到导航栏、状态栏背景的红色)。
下面是上述代码的效果:
由此可见,红色的背景延伸到了导航栏和状态栏。
在ios7适配中,布局问题是一个很头痛也很重要的问题,因为在ios7中viewController使用了全屏布局的方式,也就是说导航栏和状态栏都是不占实际空间的,状态栏默认是全透明的,导航栏默认是毛玻璃的透明效果。
方案一:
self.navigationController.navigationBar.translucent = NO;
这句话的意思就是让导航栏不透明且占空间位置,所以我们的坐标就会从导航栏下面开始算起。
方案二:
self.edgesForExtendedLayout = UIRectEdgeNone;设置不延伸到导航栏的区域
edgesForExtendedLayout是ios7的新属性,所以在ios7以下设备会出现奔溃现象,解决办法就是先判断在使用,可以通过判断系统 版本,也可以通过判断方法是否可使用
if ([self respondsToSelector:@selector(setEdgesForExtendedLayout:)])
edgesForExtendedLayout默认的值是UIRectEdgeAll就是全部布局的意思,改成UIRectEdgeNone就会和ios7一起的系统版本一样 的效果
这个值只在当前视图有navigationBar或者tabBar时有效,如果是自定义的navigationBar/tabBar,这个值是不起作用的。它标示从上下左右方向页面延伸,也就是导航栏页面也算在视图显示的部分。iOS7默认是全屏布局,取值就是UIRectEdgeAll。self.edgesForExtendedLayout = UIRectEdgeNone才能在iOS 7上显示没有问题。
同理的还有[都是在有navigationBar/tabBar时有效];
方案三:
为ios7单独定制位置,通过判断系统版本,个性为ios7定制位置。
const BOOL is_ios7 = [[[UIDevice currentDevice] systemVersion] floatValue] < 7.0;
int y= is_ios7 ? 64 : 0;
extendedLayoutIncludesOpaqueBars //不透明的操作栏
这个属性是对前面的补充,如果状态栏是不透明的,view将不会延伸到状态栏,除非将该属性的值设置为YES
2、automaticallyAdjustsScrollViewInsets
该属性在当你的view是UIScrollView或类似的ScrollView(比如UITableView)的时候使用。你想让tableview从导航栏的底部开始显示,否则就无法看到tableview的全部内容(部分cell将会被导航栏挡住),同时你又想在滚动屏幕的时候tableview能充满整个屏幕。此时,设置edgesForExtendedLayout=None没有效果,因为tableview会紧接导航栏开始显示,当你滚动的时候也不会隐藏到导航栏。
这个属性就是为了解决这个问题,如果你由viewcontroller自动调整insents(设置该属性为YES,也是默认设置),它会在table的顶部加上inset,这样显示的时候table就能从导航栏底部开始,而滚动的时候,又能延伸整个屏幕。
automaticallyAdjustsScrollViewInsets = NO的效果:
automaticallyAdjustsScrollViewInsets = YES (默认值)的效果:
上面两种情况下,table视图都会滚动到导航栏后面,但是第二种情况下,table视图的显示是紧接导航栏开始的,第一种情况导航栏覆盖了一部分数据。
3. 样式
在ios开发中UITableView是最常用的控件,ios7对于UITableView的改动也是非常大的。
1).布局上
上面说的ios7的初始化位置都是从屏幕开始的,但是如果你使用UITableView全屏显示会发现他的位置是正确的,而且导航栏的毛玻璃效果闪闪发亮。那是因为在ios7的controller中增加了automaticallyAdjustsScrollViewInsets 属性,默认值为YES。他的作用就是如果视图中有唯一的ScrollView存在,那么它会自动改变ScrollView中contentView的位置,让其不会让导航栏挡住,也能让ContentView移上去的时候在导航栏后面显示。
当然,然后视图里的ScrollView不满足系统的要求,我们就需要自己控制contentView的位置了:
UIEdgeInsets contentInset = self.tableView.contentInset;
contentInset.top = 64;
[self.tableView setContentInset:contentInset];
这样也就是达到了automaticallyAdjustsScrollViewInsets属性的效果
2.ios7上的tableView样式有很大的改动,尤其是grouped样式下。
我们可以看到ios7中cell的分割线是默认不会画满的,空出的位置大小是会根据cell.imageView的大小决定了。如果你他能跟ios6一样的效果,值需要将cell的separatorInset属性的left值改成0即可。
4. 修改样式
ios7statusBar默认色,随背景颜色深浅改变,优先黑色
随背景颜色深浅改变,优先白色
黑色透明
第一步在里面添加设置为:NO
第二步在入口类中写:[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent];
5.其他问题
背景问题
在中的背景默认是,而中默认是白色
样式问题
在ios7中UIButton默认是没有背景框的,在ios6中有明显的默认边框
一,iOS7 UITableViewCell适配
(1)iOS7 UITableViewCell背景色
在iOS7之前UITableViewCell的backgroundColor是透明的,但在iOS7中默认白色背景,如果使用iOS7 SDK的UITableViewCell显示不正常,只需要需修改:
[cell setBackgroundColor:[UIColor clearColor]];
(2)iOS7 UITableViewCell层次关系
iOS7之前,遇到UITableViewCell上的UIButton子视图找到该UITableViewCell时,也许会有这样的代码: [[sender superview] superview]
这段代码在iOS7上肯定会崩溃。
iOS7以前,我们一般是把视图添加到UITableViewCell的contentView上,contentView的父视图是UITableViewCell,上面的代码是没有问题的。但在iOS7上,UITableViewCell的contentView的父视图是UITableViewCellContentView[SDK中好像没有这个类的详细介绍],所以 [[sender superview] superview]就找不到UITableViewCell。对UiscrollView不明确的看IOS研究之滚动视图UIScrollView的简单应用
实际上这里的正确做法应该是:
在继承UITableView的类中实现UIButton的触发方法:
123456 | -(void)buttonClick:(UIButton *)button{ CGPoint buttonPosition = [button convertPoint:CGPointZero toView:self]; NSIndexPath *indexPath = [self indexPathForRowAtPoint:buttonPosition]; UITableViewCell *cell = (UITableViewCell *)[self cellForRowAtIndexPath:indexPath]; //do something |