最近一周都在调试OC项目中的bug.
枚举中定义的值,存入数据库中再取出来就改变了
之前定义了一个枚举, 里面有一个枚举项是Error,我给它赋值为-9999
/**
车的控制器类型
*/
typedef NS_ENUM(NSUInteger, CarAuthType) {
/**
通过网络请求进行控制
*/
CarAuthTypeSmartTravel = 10010, // 智慧出行
CarAuthTypeGeofence = 10017, // 电子围栏
CarAuthTypeWifi = 10001, // 车载Wifi
CarAuthTypeCarflow = 10003, // 车载流量
CarAuthTypeCarTrack = 10004, // 车辆追踪
CarAuthTypeTrafficReport = 10005, // 车况报告
CarAuthTypeDrivingReport = 10006, // 驾驶行为
CarAuthTypeLllegal = 10007, // 违章查询
CarAuthTypeTrackList = 10008, // 行车日志
CarAuthTypeError = -9999, // 类型错误
/*
本地控制
*/
CarAuthTypeOnlineStore = 1000, // 在线商店
CarAuthTypeMapUpdate = 1001, // 地图升级
CarAuthTypeCallService = 1002, // 一键呼叫
CarAuthTypeUpweek = 1003, // 预约保养
CarAuthTypeAccountControl = 1004, // 账号模块
CarAuthTypeDiscover = 1005, // 发现模块
};
然后我需要将其与网络请求获取的code码进行匹配,下面这种写法看起来很奇葩,比如网络请求返回的code为10010,但是我还是用OC的枚举表示,并且使用switch,这里借鉴的是Swift中的匹配模式的思路,一般情况下大家更喜欢在这里使用if else if else 结构.
/**
通过serviceCode获取业务类型
悲剧的OC 这个枚举不是一个对象,所以不能返回nil 我不得不定义了Error类型
@param serviceCode 业务码
@return 业务类型
*/
- (CarAuthType)getCarAuthTypeFromServiceCode:(NSString *)serviceCode {
NSInteger code = ((NSNumber *)serviceCode).integerValue;
switch (code) {
case CarAuthTypeSmartTravel:
return CarAuthTypeSmartTravel;
case CarAuthTypeGeofence:
return CarAuthTypeGeofence;
case CarAuthTypeWifi:
return CarAuthTypeWifi;
case CarAuthTypeCarflow:
return CarAuthTypeCarflow;
case CarAuthTypeCarTrack:
return CarAuthTypeCarTrack;
case CarAuthTypeTrafficReport:
return CarAuthTypeTrafficReport;
case CarAuthTypeDrivingReport:
return CarAuthTypeDrivingReport;
case CarAuthTypeLllegal:
return CarAuthTypeLllegal;
case CarAuthTypeTrackList:
return CarAuthTypeTrackList;
default:
return CarAuthTypeError;
}
}
最后我要将这个业务类型保存到数据库中,使用的数据库框架是FMDB,使用了LKDBHelper工具进行了封装.
那么问题就来了,定义的CarAuthTypeError明明为-9999,然后写入数据库后拿出来的却是-512000,我个人觉得这个地方和数据的位数与这个负号运算符有关系
我将CarAuthTypeError定义为9999,这样话数据库写与读都没有异常.
结论:
虽然在OC中我们经常定义枚举,并且定义其值,而且有关错误的值会向负数定义,但是在数据库操作上可能会出现不必要的麻烦,所以可以将错误类型定义为较大的正整数
字符+问题
这是我在Xcode上,编写的需要传递给后台的字符串
appId=dssp&message={"message":{"body":"2组合商品(流量+多服务+地图升级)","channel":"APP","orderNo":"2019071014000059511706","payType":"TENWXPAY","productId":"45","subject":"CAPSA商城2019071014000059511706","timeOut":"","totalFee":"0.01","tradeType":"APP","vin":"VF7CAPSA000000077"}}&protocolId=TENWXPAY010401&t=1562738401861&thirdInfoId=7&userId=2667
这是后台接收到我的字符串
appId=dssp&message={"message":{"body":"2组合商品(流量 多服务 地图升级)","channel":"APP","orderNo":"2019071014000059511706","payType":"TENWXPAY","productId":"45","subject":"CAPSA商城2019071014000059511706","timeOut":"","totalFee":"0.01","tradeType":"APP","vin":"VF7CAPSA000000077"}}&protocolId=TENWXPAY010401&t=1562738401861&thirdInfoId=7&userId=2667
注意看其中的细微差别没有, 注意body中文字,iOS端是有+号的,而后台Java解析后是没有+的号.
其实这个位置的问题是我们前后端 都要用同一个Key拼接后取md5,然后做校验,明显的前后端的字符串不一样,那么获取的md5也会不一样.
其实这里的主要问题就是iOS对字符串的编码问题,对于上面的字符串,其实我们不应该直接用这种原始的编码,而是要做一点过滤
NSString *body = [[NSString stringWithFormat:@"appId=%@&userId=%@&protocolId=%@&thirdInfoId=%@&t=%@&h=%@&message=%@",request.appId,request.userId,request.protocolId,request.thirdInfoId,request.t,request.h,request.message] stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet characterSetWithCharactersInString:@"#%<>[\\]^`{|}\"]+"].invertedSet];
NSLog(@"body: %@", body);
其实这个问题在Alamofire中已经有很明显的代码,自己在阅读的时候,看到过却没有去深究其原因,这也是自己的问题呀
/// Returns a percent-escaped string following RFC 3986 for a query string key or value.
///
/// RFC 3986 states that the following characters are "reserved" characters.
///
/// - General Delimiters: ":", "#", "[", "]", "@", "?", "/"
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
///
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
/// should be percent-escaped in the query string.
///
/// - parameter string: The string to be percent-escaped.
///
/// - returns: The percent-escaped string.
public func escape(_ string: String) -> String {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowedCharacterSet = CharacterSet.urlQueryAllowed
allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
var escaped = ""
//==========================================================================================================
//
// Batching is required for escaping due to an internal bug in iOS 8.1 and 8.2. Encoding more than a few
// hundred Chinese characters causes various malloc error crashes. To avoid this issue until iOS 8 is no
// longer supported, batching MUST be used for encoding. This introduces roughly a 20% overhead. For more
// info, please refer to:
//
// - https://github.com/Alamofire/Alamofire/issues/206
//
//==========================================================================================================
if #available(iOS 8.3, *) {
escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
} else {
let batchSize = 50
var index = string.startIndex
while index != string.endIndex {
let startIndex = index
let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
let range = startIndex..<endIndex
let substring = string[range]
escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? String(substring)
index = endIndex
}
}
return escaped
}
网友评论