Почему возвращаемое значение String.addingPercentEncoding() необязательно?
Подпись String
метод уклонения процентов:
func addingPercentEncoding(withAllowedCharacters: CharacterSet)
-> String?
(Это было stringByAddingPercentEncodingWithAllowedCharacters
в Swift 2.)
Почему этот метод возвращает необязательный?
В документации сказано, что метод возвращает nil "если преобразование невозможно", но неясно, при каких обстоятельствах выходящее преобразование может завершиться неудачей:
Символы экранируются с помощью UTF-8, который является полной кодировкой Unicode. Любой действительный символ Unicode может быть закодирован с использованием UTF-8 и, следовательно, может быть экранирован.
Я подумал, что, возможно, метод применяет какую-то проверку исправности для плохих взаимодействий между набором разрешенных символов и символами, используемыми для экранирования, но это не так: метод завершается успешно, независимо от того, содержит ли набор разрешенных символов "%", и также успешно, если разрешенный набор символов пуст.
В существующем состоянии необязательное возвращаемое значение, по-видимому, вызывает бессмысленную проверку ошибок.
2 ответа
Я подал в Apple отчет об ошибке и получил ответ - с очень полезным ответом, не меньше!
Оказывается (к моему большому удивлению), что можно успешно создавать строки Swift, которые содержат недопустимый Unicode в виде непарных суррогатных символов UTF-16. Такая строка может привести к сбою кодировки UTF-8. Вот некоторый код, который иллюстрирует это поведение:
// Succeeds (wat?!):
let str = String(
bytes: [0xD8, 0x00] as [UInt8],
encoding: String.Encoding.utf16BigEndian)!
// Returns nil:
str.addingPercentEncoding(withAllowedCharacters:
CharacterSet.alphanumerics)
Основанный на ответе Пола Кантрелла, небольшая демонстрация того, что этот же метод также может возвращать ноль в Objective-C, несмотря на то, что String и NSString - разные звери, когда дело касается кодировок:
uint8_t bytes[2] = { 0xD8, 0x00 };
NSString *string = [[NSString alloc] initWithBytes:bytes length:2 encoding:NSUTF16BigEndianStringEncoding];
// \ud800
NSLog(@"%@", string);
NSString *escapedString = [string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
// (null)
NSLog(@"%@", escapedString);
Ради интереса https://r12a.github.io/app-conversion/ будет сбрасывать проценты так же, как:
Ошибка%20in%20convertUTF162Char%3A%20low%20surrogate%20expected%2C%20b%3D0%21%00