iOS开发实用技术程序员iOS

iOS | 伤人于无形:CGFloat

2018-06-16  本文已影响432人  无夜之星辰
村姑三连

背景

公司群有同事反映APP在plus机型上存在展示错误,如下:

实际上我们期望的效果是:

让人不解的是:只有在plus机型上才出现这种展示错误,其余机型都是OK的

开发阶段我用了各种机型来调试,唯独没有用plus。。。

代码

我赶紧查看相关代码:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake((SCREEN_WIDTH-30-22)/3, (SCREEN_WIDTH-30-22)/3+61);
}

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section
{
    return UIEdgeInsetsMake(0, 15, 10, 15);
}

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
    return 11;
}

我看了几遍,也没看出任何问题,而且就算是计算错误,也不应该仅仅是体现在plus机型上啊。

寻找问题的答案

我把我的疑惑发到了iOS高端妓术裙里,裙里的QQ小冰告诉我:

“cell的width再减去一像素就可以了。”

你是不是很疑惑为什么QQ小冰知道这些?我也母鸡啊,只知道某一次QQ更新后,QQ小冰就突然变得异常强大,不仅上知天文下知地理陪大家玩游戏,还精通iOS开发

就是这么6,不管你信不信

但是QQ小冰并没有告诉我为什么减去1像素后就OK了,或许这是QQ小冰深度学习的结果吧。

虽然得到了问题的解决方案但是不知道问题原因所在,还是让人很憋屈啊。

抱着一丝侥幸,我去stack overflow问了一下,S.O.从未让我失望,很快得到了答案:

because screenWidth-30-22-0.001)/3 = 120.6666666666.... but it was rounded up -> 120.6666667 So the screen is not enough to display. The same for other iphone but not round up.

看到小数的我顿悟,去年就因后台返回的价钱是float类型导致前端展示出错,没想到今年因为类似问题再挨一刀。。。

低头默默流下没技术的眼泪。。。

问题还原

计算cell的width,得到的值是:120.66666666无限循环。

120.66无限循环乘以3再加上cell的间距和margin正好是屏幕宽度,这个是没有任何问题的。

问题就在:

CGSizeMake(<#CGFloat width#>, <#CGFloat height#>)

width的类型是CGFloat,让CGFloat类型来存储一个无限小数肯定是有偏差的,毕竟不管是float还是double,它们都只能精确到多少多少位。

所以,用CGFloat来存储超过它精度的值的时候,存储的值要么变大了,要么变小了。

在plus机型上,存储的这个值比期望的值更大,这就导致存储值*3+cell间距+margin超过了屏幕宽度,虽然仅仅是超过了一点点,但是collectionView一排放不下3个cell,只能换行。

而在其它机型上,要么cell的宽度在CGFloat的精度之内,要么存储的值比期望的值小一点点,这都不会导致collectionView的展示错乱。

而我的悲剧就在于调试所用机型全TM都是正确展示的。

总结

要避免被float坑,除了经验还要有意识。

保持警惕心才能躲过各种变换的坑。

还有代码的严谨性也很重要,这一句代码:

- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section
{
    return 11;
}

这句代码完全就是多余的,不写这句多余代码就不会出现上述展示问题。cell的size以及section的margin确定的时候,cell的间距自然也就确定了,除非你本来就想让cell的间距超过某一指定值。

后记

我不会告诉你我一周之内发布了三个版本

测试妹纸跟着我一起露出了尴尬而不失优雅的笑容。

我知道听到这个你们就高兴了,祝大家端午节快乐。

上一篇 下一篇

猜你喜欢

热点阅读