Замена для stringByAddingPercentEscapesUsingEncoding в ios9?


112

В iOS8 и ранее я могу использовать:

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?

Ответы:


131

В сообщении об устаревании говорится (выделено мной):

Вместо этого используйте stringByAddingPercentEncodingWithAllowedCharacters (_ :), который всегда использует рекомендованную кодировку UTF-8 и кодирует определенный компонент или подкомпонент URL, поскольку каждый компонент или подкомпонент URL имеет разные правила для допустимых символов.

Так что вам нужно только предоставить адекватный NSCharacterSetаргумент. К счастью, для URL-адресов есть очень удобный метод класса, URLHostAllowedCharacterSetкоторый вы можете использовать следующим образом:

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

Обновление для Swift 3 - метод становится статическим свойством urlHostAllowed:

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

Однако имейте в виду, что:

Этот метод предназначен для процентного кодирования строки компонента или подкомпонента URL, а НЕ всей строки URL.


6
Кроме того, я настоятельно рекомендую использовать NSURLComponents, который может обрабатывать процентное кодирование за вас.
Антонио Фавата 02

1
Есть предложения, что использовать для всей строки URL?
Skill M2

1
@ SkillM2 Я думаю NSURLComponents(с каждым компонентом, закодированным в процентах с соответствующим NSCharacterSet), это правильный путь.
Антонио Фавата,

2
Вы никогда и никогда не должны пытаться кодировать всю строку URL. Это может вызвать неожиданные ошибки, а в некоторых случаях и дыры в безопасности. Единственный гарантированно правильный способ кодирования URL-адреса - это делать это по частям.
dgatwood

Отлично. Большое спасибо, дружище!
Фелипе

100

Для 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аргумент. К счастью, для URL-адресов есть очень удобный метод класса, URLHostAllowedCharacterSetкоторый вы можете использовать следующим образом:

NSCharacterSet *set = [NSCharacterSet URLHostAllowedCharacterSet]; 

Однако имейте в виду, что:

Этот метод предназначен для процентного кодирования строки компонента или подкомпонента URL, а НЕ всей строки URL.


4
Мне нравится, когда Apple упрощает жизнь. Спасибо, яблоко.
Duck

5
Что означает «Этот метод предназначен для процентного кодирования строки компонента или подкомпонента URL, а НЕ всей строки URL». ?
GeneCode 01

4
URLHostAllowedCharacterSet выдавал ошибку «Unsupported URL», я использовал URLFragmentAllowedCharacterSet, и он работал нормально.
anoop4real

1
это не работает с +, оно не будет кодировать его и будет заменено пробелом на стороне сервера, как указано в спецификации.
Торге

45

URLHostAllowedCharacterSetэто НЕ РАБОТАЕТ ДЛЯ МЕНЯ. Я использую URLFragmentAllowedCharacterSetвместо этого.

ЦЕЛЬ -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

Стоит отметить, что ни один из этих наборов не включает +. Таким образом, знаки плюса в строке будут искажены, если они будут переданы в параметрах запроса - они будут рассматриваться как пробел на стороне сервера.
Асмо Сойнио,

21

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

Вы можете использовать urlHostAllowedcharacterSet.

/// Возвращает набор символов для символов, разрешенных в подкомпоненте URL хоста.

public static var urlHostAllowed: CharacterSet { get }

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

1

Что означает «Этот метод предназначен для процентного кодирования строки компонента или подкомпонента URL, а НЕ всей строки URL». ? - GeneCode 01 сен 2016, в 8:30

Это означает, что вы не должны кодировать https://xpto.example.com/path/subpathURL-адрес, а только то, что идет после ?.

Предполагается, потому что есть варианты использования для таких случаев, как:

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!
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.