一、URL中的中文編碼問(wèn)題
在開(kāi)發(fā)中,后端提供的接口中,有個(gè)圖片的url中帶有了中文,導(dǎo)致在創(chuàng)建NSURL時(shí)返回為nil。類似下面的代碼,如果你的SDWebImage下載圖片提示錯(cuò)誤Trying to load a nil url,可能就是因?yàn)橹形木幋a問(wèn)題造成的。
NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
// 此時(shí)url為nil
NSURL *url = [NSURL URLWithString:urlString];
出現(xiàn)這種情況可以使用[NSString stringByAddingPercentEscapesUsingEncoding:]方法先將urlString轉(zhuǎn)碼為UTF8。
NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
// url.absoluteString == "http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg"
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
但是在我開(kāi)發(fā)的工程里,并不是所以u(píng)rl都沒(méi)有轉(zhuǎn)碼,已經(jīng)轉(zhuǎn)碼的url調(diào)用上面的方法會(huì)造成二次轉(zhuǎn)碼。
NSString *urlString = @"http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg";
// url.absoluteString == "http://www.baidu.com/image?name=%25E5%25BE%25AE%25E4%25BF%25A1_123.jpg"
NSURL *url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
此時(shí)我們就需要使用下面的方法。
正確的使用方式
// 該方法可以根據(jù)urlString中的內(nèi)容判斷是否轉(zhuǎn)碼,沒(méi)有轉(zhuǎn)碼才進(jìn)行轉(zhuǎn)碼
static NSString * EncodeString(NSString * uncodeString) {
return (NSString *) CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef) uncodeString, (CFStringRef)@"!$&'()*+,-./:;=?@_~%#[]",NULL,kCFStringEncodingUTF8));
}
NSString *urlString = @"http://www.baidu.com/image?name=微信_(tái)123.jpg";
NSString *urlString1 = @"http://www.baidu.com/image?name=%E5%BE%AE%E4%BF%A1_123.jpg";
// url.absoluteString == url1.absoluteString == "http://www.baidu.com/image?name=%25E5%25BE%25AE%25E4%25BF%25A1_123.jpg"
NSURL *url = EncodeString(urlString);
NSURL *url1 = EncodeString(urlString1);
CFURLCreateStringByAddingPercentEscapes("參數(shù)1","參數(shù)2","參數(shù)3","參數(shù)4","參數(shù)5");
//方法說(shuō)明
//首先返回一個(gè)CFStringRef
//參數(shù)3 不轉(zhuǎn)義字符 參數(shù)4 指定轉(zhuǎn)義字符
具體參數(shù)解釋 :
第一個(gè)參數(shù)是AllocatorRef –>內(nèi)存分配類型(內(nèi)存分配器下一節(jié)說(shuō)明)
第二個(gè)參數(shù)是CFStringRef –>待轉(zhuǎn)碼字符串
第三個(gè)參數(shù)是CFStringRef –>不轉(zhuǎn)義字符
第三個(gè)參數(shù)是CFStringRef –>指定轉(zhuǎn)義字符
第三個(gè)參數(shù)是CFStringEncoding –>編碼類型 KCFStringEncodingUTF8
這種方法有內(nèi)存泄漏一定要釋放:CFRelease(CFStringRef)
PS:CFBridgingRelease(CFStringRef) 釋放掉CFStringRef 并且轉(zhuǎn)化為NSString;
二、URL拼接字符串問(wèn)題
在工程中,因?yàn)楹蠖私涌诜祷氐膇mage都是大圖,所以需要前端在后面拼接參數(shù)thumb=1,所以想做一個(gè)通用的添加參數(shù)的方法。
url通常會(huì)有以下幾種形式:
1、https://www.baidu.com ----------------------------------------------noquery
2、https://www.baidu.com/act/index.html -------------------------------noquery
3、https://www.baidu.com/act/index.html? ------------------------------noquery but has ?
4、https://www.baidu.com/act/index.html?foo=bar ----------------------has query
5、https://www.baidu.com/act/index.html?foo1=bar1&foo2=bar2 --------has query
6、https://www.baidu.com/act/index.html?foo1=bar1&foo2=bar2#top ---has query and fragment
因?yàn)榇蟾庞猩厦鎺追N形式,所以直接用匹配的方式很復(fù)雜,不過(guò)幸好有系統(tǒng)方法可以幫我們分解url,然后合成url。
+ (NSURL *)url:(NSString *)urlString appendQuery:(NSString *)tmpQuery {
if (urlString.length == 0 || tmpQuery.length == 0) {
return nil;
}
NSURLComponents *components = [NSURLComponents componentsWithString:urlString];
NSString *query = components.query;
query = (query&&![query isEqualToString:@""])? [query stringByAppendingString:[NSString stringWithFormat:@"&%@",tmpQuery]] : tmpQuery;
// components.query會(huì)過(guò)度編碼,已經(jīng)編碼的字符串會(huì)再次轉(zhuǎn)碼一次
// components.query = query;
// components.percentEncodedQuery不會(huì)是參數(shù)轉(zhuǎn)碼,但是需要保證設(shè)置的值不能有非法字符,所以需要保證query必須是轉(zhuǎn)碼后的字符串
components.percentEncodedQuery = EncodeString(uncodeString);
return components.URL;
}
在iOS9以后CFURLCreateStringByAddingPercentEscapes:失效了
所以可以使用下面的方法替換。
static NSString * EncodeString(NSString * uncodeString) {
if (uncodeString.length == 0) {
return nil;
}
// 先嘗試使用原始字符串創(chuàng)建url
NSURL *url = [NSURL URLWithString:uncodeString];
if (url == nil) {// 如果url為nil,說(shuō)明uncodeString中含有特殊字符串,則調(diào)用下面的方法進(jìn)行轉(zhuǎn)碼
NSString *decodeString = (NSString *)CFBridgingRelease((__bridge CFTypeRef _Nullable)([uncodeString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]]));
url = [NSURL URLWithString:decodeString.length >0 ? decodeString : uncodeString];
}
return url.absoluteString;
}
參考內(nèi)容:
iOS-URL編解碼
再探URL拼接的坑