说说我所碰到的几个比较折腾的bug
vpn + reachability
之前在开发宝宝拍拍app的时候,需要监控网络状态,一旦有网络,需要尽快把本地图片上传到阿里云OSS,因为上传图片的同时,还需要把SQLite记录上传到我们自己的服务器,所以就这么写了:
reach = Reachability reachabilityWithHostname:@"http://ibbpp.com/"
本地测试了下,没问题,于是就放心提交了。
后来客户反馈说在有网状态下,图片一直没上传。
首先怀疑是服务器挂了,结果发现http://ibbpp.com/首页能正常打开。用自己的手机测试了下,也没问题。
最终发现客户的截图上显示有挂VPN,于是挂上VPN测试,果然。同时,客户在国外没挂VPN也能复现这个问题。
于是猜测很可能是网络本身的问题,比如DNS解析服务。最终的解决方案:
reach = Reachability reachabilityWithHostname:@"www.baidu.com"
当然,当我们服务器挂了,只要阿里云OSS服务没挂,图片还是能正常上传,不会影响业务逻辑。
这里有个小问题。Reachability底层使用SCNetworkReachabilityRef来监测网络状况
+(Reachability*)reachabilityWithHostname:(NSString*)hostname
{
SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
if (ref)
{
id reachability = [[self alloc] initWithReachabilityRef:ref];
return reachability;
}
return nil;
}
而SCNetworkReachabilityRef本身是不准确的:
The SCNetworkReachability programming interface allows an application to determine the status of a system’s current network configuration and the reachability of a target host. A remote host is considered reachable when a data packet, sent by an application into the network stack, can leave the local device. Reachability does not guarantee that the data packet will actually be received by the host
在局域网没有连接互联网的情况下,比如家里 WiFi能连上但宽带欠费了,SCNetworkReachability还会显示网络可用。
最好的方案还是直接调用一个自定义的服务器接口,使用短超时和特定返回来监测网络状况。或者直接Ping也行。
messageid
在IM应用中,需要记录消息的id,这个id一般位数会比较长,比如64bit。后续从数据库中取出时需要经过JSON序列化,比如
NSJSONSerialization JSONObjectWithData:self options:NSJSONReadingAllowFragments|NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves error:error
而苹果的NSJSONSerialization在iOS7和iOS7以下的系统上转换大数值时会使用NSDecimalNumber,在iOS8上会使用CFNumber。
而苹果在设计NSDecimalNumber时,只保证53bit的精度,所以任何超过这一精度的数值在JSON序列化之后,如果直接通过unsignedLongLongValue方法来获取时都可能会出错。
解决方案,先转化为字符串再转成数值:
[[decimalNumber description] longLongValue]