SwiftのURL型を正しく理解しよう!
概要
これまでなんとなくでURL型を使っていたので、URL型を操作する上で、基礎的な知識や基本操作をまとめました。
本記事では、SwiftでのURLの基本構造から、パスの操作、エンコード、ディレクトリ管理、最新のAPI仕様などをカバーしてます。
URLを正しく安全に使えるようになるために、是非ご活用ください。
URLとは
URL(Uniform Resource Locator)は、Web上のリソース(Webページ、API、ファイルなど)の アドレスを指定するための文字列です。
URLは次のような構造を持っています。
scheme://host/path?query#fragment
要素 | 説明 | 例 |
---|---|---|
スキーム (Scheme) | 通信プロトコルを指定 |
https , http , file
|
ユーザー情報 (User Info)(省略可) | 認証用のユーザー名とパスワード | user:pass@ |
ホスト (Host)(省略可) | サーバーのドメイン名または IP アドレス |
example.com , 192.168.1.1
|
ポート (Port)(省略可) | サーバーのポート番号 |
:80 , :443 , :21
|
パス (Path) | サーバー内のリソースの場所 |
/index.html , /api/users
|
クエリ (Query)(省略可) | 追加のパラメータ | ?search=swift&page=1 |
フラグメント (Fragment)(省略可) | ページ内の特定の場所を指定 | #section1 |
絶対URLと相対URL
SwiftのURL型には、絶対URLと相対URLそれぞれに対応したイニシャライザーやメソッドが用意されています。
したがって、両者の違いを理解することが重要です。
では、絶対URLと相対URLの違いを確認した上で、対応するイニシャライザーなどを見ていきましょう。
絶対URLは、スキーム(scheme)、ホスト(host)、パス(path) など、アクセス先を特定するのに必要なすべての情報を含んだ完全なURLです。
相対URLは、基準となるURL(baseURL)に対する部分的なパスです。
スキームやホストが含まれていないため、単独ではアクセスできず、基準 URLと組み合わせることで有効なURLになります。
init(string:)
絶対URLを初期化する際に使用します。
let url = URL(string: "https://www.apple.com")!
print(url) // https://www.apple.com
init(string:encodingInvalidCharacters:)
encodingInvalidCharacters
がtrueの場合、パスやクエリ部分の特殊文字が自動でエンコードされます。
falseにすると、特殊文字を含むURLはnilになります。
let url = URL(string: "https://zenn.dev/search?q=sw ift", encodingInvalidCharacters: true)!
print(url) // https://zenn.dev/search?q=sw%20ift
let fileURL = URL(string: "file:///Applications/fol der1", encodingInvalidCharacters: true)!
print(fileURL) // file:///Applications/fol%20der1
init(string:relativeTo:)
相対URLを基準URL(baseURL)に対して結合し、絶対URLを生成します。
baseURLを含むURLを出力すると、相対パス-基準URLの形式で出力されます。
let baseURL = URL.applicationDirectory
let fileURL = URL(string: "folder1", relativeTo: baseURL)!
print(fileURL) // folder1 -- file:///Applications/
print(fileURL.absoluteString) // file:///Applications/folder1
absoluteString
絶対URLをString で取得します。
let baseURL = URL.applicationDirectory
let fileURL = URL(string: "folder1", relativeTo: baseURL)!
// 絶対URL
print(baseURL.absoluteString) // file:///Applications/
// 相対URLを含むURL
print(fileURL.absoluteString) // file:///Applications/folder1
relativeString
baseURLを基準にした相対パスを取得します。
baseURLがない場合や、絶対URLに対して使用するとabsoluteString
と同じ挙動になります。
// 相対URLを含むURL
let baseURL = URL.applicationDirectory
let fileURL = URL(string: "folder1", relativeTo: baseURL)!
print(fileURL.relativeString) // folder1
// 絶対URL
let url = URL(string:"https://zenn.dev/search?q=swift")!
print(url.relativeString) // https://zenn.dev/search?q=swift
ディレクトリの取得
Swiftではアプリが使用するディレクトリをURL型のstaticプロパティを使って取得できます。
用途に応じて適切なディレクトリを選択することが重要です。
applicationDirectory
macOSの/Applications/ディレクトリを指す。
このディレクトリには通常、ユーザーがインストールしたアプリケーションが保存されます。
print(URL.applicationDirectory)
// file:///Applications/
documentsDirectory
iOS / macOS アプリがユーザーデータを保存するためのディレクトリ。
アプリがユーザーごとにデータを管理する際に使用される。
print(URL.documentsDirectory)
// file:///Users/xxxx/Library/Developer/XCPGDevices/0FFCAE8F-7803-4943-A3C6-F6C3EC197D00/data/Containers/Data/Application/238BC63A-F053-4E7F-9A1B-CA38A9F206B3/Documents/
// xxxxはユーザー名
他にも様々なディレクトリが取得できるので、気になる方はご確認ください。
URLの構成要素を取り出すメソッド
ここでは、冒頭で触れたURLの要素を取得するためのメソッドを見ていきます。
なので、冒頭の内容を思い出しながらお読みください。
SwiftではURL型の各構成要素を取得するためのメソッドが提供されています。
ただし、host
、path
、query
、fragment
などのプロパティはiOS 18.4 / macOS 15.4 などのバージョンで非推奨(deprecated)となっているため、対応するメソッドを使用する必要があります。
host(percentEncoded:)
URLのホスト(ドメイン名やIPアドレス)を取得する。
ホストが存在しない場合はnilを返します。
let url = URL(string: "https://zenn.dev/search?q=swift")!
print(url.host() ?? "nil") // zenn.dev
let url = URL.applicationDirectory.appending(path: "folder1")
print(url.host()) // nil
path(percentEncoded:)
URLのパス部分を取得する。
URLにおいてpathは常に存在するものとみなされる ため、pathがない場合は ""(空文字)として扱われます。
percentEncoded
はデフォルトtrueにで、空白などが置き換えられる。
let url = URL(string:"https://zenn.dev/search?q=swift")!
print(url.path()) // /search
// パスがない時
let url = URL(string:"https://zenn.dev")!
print(url.path()) // 何もprintされない(空文字)
// 特殊文字あり(全角スペース)
let baseURL = URL.applicationDirectory.appending(path: "fold er1")
print(baseURL) // file:///Applications/fold%E3%80%80er1
print(baseURL.path()) // /Applications/fold%E3%80%80er1
URLの構成要素を取り出すプロパティ
一部の要素(scheme
/ port
/ lastPathComponent
)は、プロパティとして直接取得可能です。
ここでは、よく使うlastPathComponent
のみ紹介します。
lastPathComponent
URLの最後のパスコンポーネント(ファイル名やフォルダ名)を取得する。
パスが存在しない場合は 空文字 ("") を返します。
let url = URL.applicationDirectory.appending(path: "folder1/sample1.txt")
print(url) // file:///Applications/folder1/sample1.txt
print(url.lastPathComponent) // sample1.txt
// パスがない時
let url = URL(string: "https://zenn.dev")!
print(url.lastPathComponent) // 何もprintされない(空文字を返す)
URLの結合と削除
URLの結合と削除のメソッドは、下記のような命名の違いを理解しておくとわかりやすいと思います。
ここでは、appending
とdeleting
のみ紹介します。
- append/deleteは戻り値なし
- appending/deletingは新しいURLを返す
appending(component:directoryHint:)
既存のURLにコンポーネントを追加する。
ファイルを追加する場合は.notDirectory
、フォルダの場合は.isDirectory
を指定する。
※ directoryHint
を省略すると自動で推論される。
特殊文字が含まれた場合は、encodeされる。
let baseURL = URL.applicationDirectory.appending(path: "folder1")
let newFilePath = baseURL.appending(component: "sample1.txt", directoryHint: .notDirectory)
print(newFilePath) // file:///Applications/folder1/sample1.txt
// 特殊文字(半角スペース)
let baseUrl = URL.applicationDirectory.appending(path: "folder1")
let newFilePath = baseUrl.appending(component: "sam ple1.txt", directoryHint: .notDirectory)
print(newFilePath) // file:///Applications/folder1/sam%20ple1.txt
appending(path:directoryHint:)
パスを利用してURLに追加する。
基本的にappending(component:)
と同じだが、/ を含むパスを渡せる点が異なる。
特殊文字が含まれた場合は、path(percentEncoded:)
と同様にencodeされる。
let url = URL.applicationDirectory.appending(path: "folder1/sample1.txt")
print(url) // file:///Applications/folder1/sample1.txt
// 特殊文字ありの時(半角スペース)
let url = URL.applicationDirectory.appending(path: "fold er1")
print(url) // file:///Applications/fold%20er1
appending(components:directoryHint:)
複数のパスコンポーネントを一括で追加する。
// ディレクトリ
let url = URL.applicationDirectory
print(url.appending(components: "folder1", "folder2", "folder3", directoryHint: .isDirectory)) // file:///Applications/folder1/folder2/folder3/
// ディレクトリとファイル
let url = URL.applicationDirectory
print(url.appending(components: "folder1", "folder2", "file.txt", directoryHint: .notDirectory)) // file:///Applications/folder1/folder2/file.txt
appendingPathComponent(_:confirmingTo:)
特定のファイル形式(UTI)に準拠したパスを追加する。
⚠️引数がconfirmingTo以外の同一名のメソッドは、deprecatedになっているので注意
let url = URL.applicationDirectory
print(url.appendingPathComponent("sample1", conformingTo: .plainText)) // file:///Applications/sample1.txt
appendPathExtension(for:)
指定したユニフォームタイプ識別子(UTI)に適した拡張子を追加する。
let url = URL.applicationDirectory
let filePath = url.appending(component: "sample1").appendingPathExtension(for: .plainText)
print(filePath) // file:///Applications/sample1.txt
deletingPathExtension
URLの拡張子を削除する。
⚠️ パスがない場合は何も変更されない
let url = URL.applicationDirectory.appending(path: "folder1/sample1.txt")
print(url.deletingPathExtension()) // file:///Applications/folder1/sample1
// 🕵️🕵️🕵️🕵️🕵️🕵️🕵️
// パスが存在しない場合は何も変更しない
let baseURL = URL(string: "http://www.example.com")!
print(baseURL.deletingLastPathComponent()) // http://www.example.com
deletingLastPathComponent
URLの最後のパスコンポーネント(ファイルやフォルダ)を削除する。
⚠️ パスがない場合は何も変更されない
let url = URL.applicationDirectory.appending(path: "folder1/sample1.txt")
print(url.deletingLastPathComponent()) // file:///Applications/folder1/
// 🕵️🕵️🕵️🕵️🕵️🕵️🕵️
// パスが存在しない場合は何も変更しない
let baseURL = URL(string: "http://www.example.com")!
print(baseURL.deletingLastPathComponent()) // http://www.example.com
参考記事
Discussion