Документ URLComponents.init(url:resolvingAgainstBaseURL:)
говорит:
Returns the initialized URL components object, or nil if the URL could not be parsed.
Знаю это:
Я предполагаю, что инициализация URLComponents
завершится ошибкой, если URL-адрес соответствует RFC 1808/1738/2732, но не RFC 3986. Что это за URL? Любой пример?
Единственный намек, который у меня есть, насколько разница может быть связана с разными зарезервированными символами?
Давайте рассмотрим его из исходного кода, поскольку Swift Foundation является открытым исходным кодом.
Инициализатор URLComponents
реализован в яблоко/свифт – URLComponents.swift и apple/swift-corelibs-foundation – URLComponents.swift и просто вызывает инициализатор NSURLComponents
.
Инициализатор NSURLComponents
реализован в apple/swift-corelibs-foundation – NSURL.swift и просто вызывает _CFURLComponentsCreateWithURL
.
_CFURLComponentsCreateWithURL
реализован в apple/swift-corelibs-foundation — CFURLComponents.c и выполняет:
CFURLCopyAbsoluteURL
_CFURLComponentsCreateWithString
, которое вызывает:
_CFURIParserParseURIReference
+ неудачный _CFURIParserURLStringIsValid
CFURLCopyAbsoluteURL
реализован в apple/swift-corelibs-foundation – CFURL.c и не работает только для:
#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
if ( base && CFURLIsFileReferenceURL(base) && !CFURLHasDirectoryPath(base) ) {
// 16695827 - If the base URL is a file reference URL which doesn't end with a slash, we have to convert it to a file path URL before we can make it absolute.
base = CFURLCreateFilePathURL(alloc, base, NULL);
if ( !base ) {
// could not convert file reference URL to file path URL -- fail will NULL
return NULL;
}
}
#endif
Реализация CFURLCreateFilePathURL
находится в opensource.apple.com/source/CF — CFURL.c, и я понимаю, что она завершится ошибкой только в том случае, если нет схемы или пути, что невозможно, поскольку мы ранее проверяли файловую схему или существование файла с помощью CFURLIsFileReferenceURL
.
_CFURIParserParseURIReference
реализован в apple/swift-corelibs-foundation — CFURLComponents_URIParser.c и будет давать сбой только в том случае, если длина URL-адреса превышает 2 ГБ, что, как я полагаю, не связано со спецификациями RFC.
_CFURIParserURLStringIsValid
по существу вызовет _CFURIParserValidateComponent
для каждого компонента и завершится ошибкой для недопустимых символов или escape-последовательностей. Это, пожалуй, самая актуальная часть.
Теперь, немного поэкспериментировав, мы знаем, что нам нужна схема (например, https://
или просто a://
), и мы играем с зарезервированными символами, чтобы придумать такие примеры, как:
// OK
let url = URL(string: "a://@@")!
// CRASH
let components = URLComponents(url: url, resolvingAgainstBaseURL: true)!
Попытка альтернативного инициализатора URLComponents
также потерпит неудачу, поэтому не пытайтесь думать, что он другой:
// CRASH
let components = URLComponents(string: url.absoluteString)!
"a://@@"
является примером действительного NSURL, но недопустимого RFC 3986.
Кстати, некоторые пользователи Swift, похоже, хотят в будущем унифицировать поддержку URL и URLComponents (больше никаких различий RFC) как показано в URL.swift:
// Future implementation note:
// NSURL (really CFURL, which provides its implementation) has quite a few quirks in its processing of some more esoteric (and some not so esoteric) strings. We would like to move much of this over to the more modern NSURLComponents, but binary compat concerns have made this difficult.
// Hopefully soon, we can replace some of the below delegation to NSURL with delegation to NSURLComponents instead. It cannot be done piecemeal, because otherwise we will get inconsistent results from the API.
Я не уверен, как они планируют это сделать, так как это будет означать, что либо URL(string: "a://@@")
потерпит неудачу, либо URLComponents(string: "a://@@")
преуспеет.
Умная колбаса :-)
Это действительно интересно, спасибо! Также помог мне избавиться от одной красной строки, которая беспокоила меня в моем отчете о покрытии кода, хотя это такой крайний случай!