Превращаем NSURL в NSString в Swift: полный гайд с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Знакомство с задачей: почему NSURL и NSString так важны?

Каждый iOS-разработчик рано или поздно сталкивается с задачей: у вас есть объект NSURL, но вам нужно получить из него обычную строку — NSString (или, в современном Swift, просто String). Казалось бы, что может быть проще? Однако здесь скрывается множество подводных камней: от неправильного декодирования символов до потери фрагментов URL.

На Stack Overflow вопрос «Convert an NSURL to an NSString» собрал тысячи просмотров — это настоящая классика. Мы в PythonLib решили разобрать тему досконально, чтобы вы больше никогда не теряли время на поиски решения. Поехали!

Что такое NSURL и NSString в Swift?

Прежде чем переходить к коду, давайте быстро вспомним, с чем мы имеем дело.

NSURL — это объект, представляющий унифицированный указатель ресурса (URL). Он умеет разбирать адреса на компоненты: схему, хост, путь, параметры и так далее. В Swift ему на смену пришел нативный тип URL, но NSURL до сих пор активно используется в старом коде, Core Foundation и при работе с Objective-C библиотеками.

NSString — это строка в Objective-C, которая в Swift автоматически мостится (bridges) к типу String. Поэтому, когда мы говорим «преобразовать NSURL в NSString», мы на самом деле получаем либо String, либо NSString?.

Основные способы конвертации NSURL в NSString

Давайте разберем три главных подхода. Каждый из них подходит для разных сценариев.

1. Использование свойства absoluteString

Самый популярный и простой способ. Свойство absoluteString возвращает полную строку URL, включая все компоненты.

import Foundation

let url = NSURL(string: "https://pythonlib.ru/swift-guide?page=1&lang=ru")!
let urlString = url.absoluteString

print(urlString) // "https://pythonlib.ru/swift-guide?page=1&lang=ru"

Важно: absoluteString возвращает строку, которая может содержать процентное кодирование (percent-encoding). Например, пробелы будут выглядеть как %20, а кириллица — как %D0%9F.

2. Свойство relativeString

Если ваш URL является относительным (не содержит схемы и хоста), relativeString вернет только относительную часть.

let baseURL = NSURL(string: "https://pythonlib.ru")!
let relativeURL = NSURL(string: "swift-guide", relativeTo: baseURL)!

let absolute = relativeURL.absoluteString
let relative = relativeURL.relativeString

print(absolute) // "https://pythonlib.ru/swift-guide"
print(relative) // "/swift-guide"

Этот метод особенно полезен, когда вы работаете с базовыми URL и относительными путями.

3. Разбор компонентов URL вручную

Иногда вам не нужен полный URL, а только его часть: путь, хост или параметры. Для этого используйте свойства NSURLComponents или прямое обращение к NSURL.

let url = NSURL(string: "https://pythonlib.ru/ios/guide?query=swift#section1")!

let scheme = url.scheme ?? ""
let host = url.host ?? ""
let path = url.path ?? ""
let query = url.query ?? ""
let fragment = url.fragment ?? ""

print("Схема: \(scheme)")
print("Хост: \(host)")
print("Путь: \(path)")
print("Параметры: \(query)")
print("Якорь: \(fragment)")

Этот подход дает максимальный контроль над тем, что именно вы извлекаете.

Типичные ошибки и как их избежать

Даже опытные разработчики иногда спотыкаются на простых вещах. Вот три самые частые проблемы при конвертации NSURL в NSString.

Ошибка 1: Забываем про опциональность

NSURL(string:) возвращает опциональный тип NSURL?. Если строка не является валидным URL, вы получите nil. Попытка вызвать absoluteString на nil приведет к крашу.

let badString = "это не URL"
let badURL = NSURL(string: badString)
// badURL = nil

// Опасный код:
// let result = badURL!.absoluteString // CRASH!

// Безопасный код:
if let validURL = badURL {
    let result = validURL.absoluteString
    print(result)
} else {
    print("Не удалось создать NSURL")
}

Ошибка 2: Игнорирование процентного кодирования

URL с кириллицей, пробелами или спецсимволами требует декодирования. absoluteString возвращает закодированную версию. Чтобы получить человекочитаемую строку, используйте removingPercentEncoding.

let encodedURL = NSURL(string: "https://pythonlib.ru/%D1%81%D1%82%D0%B0%D1%82%D1%8C%D1%8F")!
let encodedString = encodedURL.absoluteString
let decodedString = encodedString.removingPercentEncoding ?? encodedString

print("Закодировано: \(encodedString)")
print("Декодировано: \(decodedString)")

Ошибка 3: Путаница между absoluteString и path

Свойство path возвращает только путь URL (без схемы, хоста и параметров). Многие новички ожидают, что path вернет полный адрес.

let url = NSURL(string: "https://pythonlib.ru/ios/guide?version=2")!
print(url.absoluteString) // "https://pythonlib.ru/ios/guide?version=2"
print(url.path ?? "")     // "/ios/guide"

Современный Swift: работа с типами URL и String

Начиная с Swift 3, Apple рекомендует использовать нативные типы URL и String вместо NSURL и NSString. Однако, если вы работаете с устаревшим кодом или библиотеками, миграция может быть неполной. Вот как выглядит та же задача на современном Swift:

// Создание URL
let url = URL(string: "https://pythonlib.ru/swift-guide")!

// Преобразование в String
let urlString = url.absoluteString

// Безопасное извлечение компонентов
if let components = URLComponents(url: url, resolvingAgainstBaseURL: false) {
    let host = components.host ?? ""
    let path = components.path
    let queryItems = components.queryItems
    print("Хост: \(host), Путь: \(path)")
}

// Декодирование
let decodedPath = url.path.removingPercentEncoding ?? url.path
print("Декодированный путь: \(decodedPath)")

Обратите внимание: URL автоматически мостится к NSURL, поэтому вы можете использовать оба типа в одном проекте.

Практические примеры из реальной жизни

Теория хороша, но практика лучше. Вот три сценария, где конвертация NSURL в NSString встречается чаще всего.

Блоги

Рекомендаций по книгам