iOS 9中用于替代stringByAddingPercentEscapesUsingEncoding的方法是什么?

117
在iOS 8及之前,我可以使用:

In iOS8 and prior I can use:

NSString *str = ...; // some URL
NSString *result = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

iOS9中stringByAddingPercentEscapesUsingEncoding已被替换为stringByAddingPercentEncodingWithAllowedCharacters

NSString *str = ...; // some URL
NSCharacterSet *set = ???; // where to find set for NSUTF8StringEncoding?
NSString *result = [str stringByAddingPercentEncodingWithAllowedCharacters:set];

我的问题是:在哪里找到需要的NSCharacterSet (NSUTF8StringEncoding),以便正确替换stringByAddingPercentEscapesUsingEncoding

8个回答

134

废弃消息提示(重点在强调部分):

使用stringByAddingPercentEncodingWithAllowedCharacters(_ :)代替,该方法始终使用推荐的UTF-8编码,并对每个URL组件或子组件进行编码,因为每个URL组件或子组件具有不同的有效字符规则。

这意味着你只需要提供一个合适的NSCharacterSet作为参数。幸运的是,对于URLs,有一个非常实用的类方法叫做URLHostAllowedCharacterSet可以像下面这样使用:

let encodedHost = unencodedHost.stringByAddingPercentEncodingWithAllowedCharacters(.URLHostAllowedCharacterSet())

更新至 Swift 3 -- 方法变为静态属性urlHostAllowed:

let encodedHost = unencodedHost.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)

请注意,:

此方法旨在对URL组件或子组件字符串进行百分号编码,而不是对整个URL字符串进行编码。


请注意,:

此方法旨在对URL组件或子组件字符串进行百分号编码,而不是对整个URL字符串进行编码。


6
我强烈建议使用NSURLComponents,可以为您处理百分号编码。 - Antonio Favata
1
有什么建议用于整个URL字符串? - ajeetdl
1
@SkillM2 我认为使用NSURLComponents(每个组件都使用相应的NSCharacterSet进行百分比编码)是正确的方法。 - Antonio Favata
2
你绝不能尝试编码整个URL字符串。这可能会导致意外的错误,并在某些情况下造成安全漏洞。编码URL的唯一保证正确的方法是逐个部分进行编码。 - dgatwood
你如何在Swift 3中实现这个? - Joseph Astrahan
显示剩余2条评论

102

对于Objective-C:

NSString *str = ...; // some URL
NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet]; 
NSString *result = [str stringByAddingPercentEncodingWithAllowedCharacters:set];

在哪里找到用于NSUTF8StringEncoding的字符集?

对于六个URL组件和子组件,有预定义的字符集可用于百分号编码。将这些字符集传递给 -stringByAddingPercentEncodingWithAllowedCharacters: 方法。

 // Predefined character sets for the six URL components and subcomponents which allow percent encoding. These character sets are passed to -stringByAddingPercentEncodingWithAllowedCharacters:.
@interface NSCharacterSet (NSURLUtilities)
+ (NSCharacterSet *)URLUserAllowedCharacterSet;
+ (NSCharacterSet *)URLPasswordAllowedCharacterSet;
+ (NSCharacterSet *)URLHostAllowedCharacterSet;
+ (NSCharacterSet *)URLPathAllowedCharacterSet;
+ (NSCharacterSet *)URLQueryAllowedCharacterSet;
+ (NSCharacterSet *)URLFragmentAllowedCharacterSet;
@end

弃用警告信息说(重点在于):

使用stringByAddingPercentEncodingWithAllowedCharacters(_:),它总是使用推荐的UTF-8编码,并为特定的URL组件或子组件进行编码,因为每个URL组件或子组件具有不同的规则以确定哪些字符是有效的。

所以你只需要提供一个足够的NSCharacterSet作为参数。幸运的是,对于URLs,有一个非常方便的类方法叫做URLHostAllowedCharacterSet,你可以像这样使用它:

NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet]; 

请注意,这种方法旨在对URL组件或子组件字符串进行百分比编码,而不是整个URL字符串。


4
我喜欢苹果让生活变得更加简单。谢谢你,苹果。 - Duck
5
这个方法的意思是将URL组件或子组件字符串进行百分号编码,而不是整个URL字符串。 - GeneCode
4
URLHostAllowedCharacterSet 导致“不支持的 URL”错误,我改为使用 URLFragmentAllowedCharacterSet,现在可以正常工作了。 - anoop4real
1
这个无法使用+号进行编码,根据规范,在服务器端它会被替换为空格。 - Torge

51

URLHostAllowedCharacterSet 对我来说不起作用。我改用 URLFragmentAllowedCharacterSet

OBJECTIVE-C

NSCharacterSet *set = [NSCharacterSet URLFragmentAllowedCharacterSet];
NSString * encodedString = [@"url string" stringByAddingPercentEncodingWithAllowedCharacters:set];

SWIFT - 4

"url string".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
以下是有用的(倒置)字符集:
URLFragmentAllowedCharacterSet  "#%<>[\]^`{|}
URLHostAllowedCharacterSet      "#%/<>?@\^`{|}
URLPasswordAllowedCharacterSet  "#%/:<>?@[\]^`{|}
URLPathAllowedCharacterSet      "#%;<>?[\]^`{|}
URLQueryAllowedCharacterSet     "#%<>[\]^`{|}
URLUserAllowedCharacterSet      "#%/:<>?@[\]^`

谢谢,你也一样。 - Arpit B Parekh
值得注意的是,这些集合中都不包括 +。因此,如果在查询参数中传递字符串中的加号,则会出现混乱 - 在服务器端被视为空格 - Asmo Soinio
实际上,加号+会被编码为%2B,所以不用担心。它会正常工作的。@AsmoSoinio - Lal Krishna

22

Objective-C

这段代码对我有用:

urlString = [urlString stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLFragmentAllowedCharacterSet]];

4

Swift 2.2:

extension String {
 func encodeUTF8() -> String? {
//If I can create an NSURL out of the string nothing is wrong with it
if let _ = NSURL(string: self) {

    return self
}

//Get the last component from the string this will return subSequence
let optionalLastComponent = self.characters.split { $0 == "/" }.last


if let lastComponent = optionalLastComponent {

    //Get the string from the sub sequence by mapping the characters to [String] then reduce the array to String
    let lastComponentAsString = lastComponent.map { String($0) }.reduce("", combine: +)


    //Get the range of the last component
    if let rangeOfLastComponent = self.rangeOfString(lastComponentAsString) {
        //Get the string without its last component
        let stringWithoutLastComponent = self.substringToIndex(rangeOfLastComponent.startIndex)


        //Encode the last component
        if let lastComponentEncoded = lastComponentAsString.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.alphanumericCharacterSet()) {


        //Finally append the original string (without its last component) to the encoded part (encoded last component)
        let encodedString = stringWithoutLastComponent + lastComponentEncoded

            //Return the string (original string/encoded string)
            return encodedString
        }
    }
}

return nil;
}
}

2

针对Swift 3.0版本,您可以使用urlHostAllowed字符集。

/// 返回在主机URL子组件中允许的字符集。

public static var urlHostAllowed: CharacterSet { get }

WebserviceCalls.getParamValueStringForURLFromDictionary(settingsDict as! Dictionary<String, AnyObject>).addingPercentEncoding(withAllowedCharacters: CharacterSet.urlHostAllowed)

1
这句话的意思是,“该方法旨在对URL组件或子组件字符串进行百分号编码,而不是整个URL字符串。”- GeneCode Sep 1 '16 at 8:30。这意味着您不应该对url的https://xpto.example.com/path/subpath 进行编码,而只需对?后面的内容进行编码。但也有一些特殊情况需要对整个URL进行编码。
https://example.com?redirectme=xxxxx

其中xxxxx是完全编码过的URL。


0

补充接受的答案。 考虑到这个注释

此方法旨在对URL组件或子组件字符串进行百分号编码,而不是整个URL字符串。

整个URL不应该被编码:

let param = "=color:green|\(latitude),\(longitude)&\("zoom=13&size=\(width)x\(height)")&sensor=true&key=\(staticMapKey)".addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) 
let url = "https://maps.google.com/maps/api/staticmap?markers" + param!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接