URL 처리 방법 - ehrldyd15/Swift_Skills GitHub Wiki

URL 처리 방법

URL과 URI 구분

URI(Uniform Resource Identifier): 특정 리소스 식별자

URL(Uniform Resource Location): 특정 리소스 위치

  • URI의 방법중 하나가 URL

스크린샷 2022-08-01 오전 10 09 42

URL의 구조

스크린샷 2022-08-01 오전 10 10 43

  • scheme: 사용할 프로토콜

  • host: 접근할 서버의 호스트 이름

  • path: 접근할 서버의 경로에 대한 정보

  • query: 접근할 대상에 전달하는 추가적인 정보 (= 파라메터)

Swift에서 URL 접근

let urlString = "https://ios-development.tistory.com/ios?page=1&item=2"
guard let url = URL(string: urlString) else { return }

// url의 기본 요소 접근
url.absoluteString // urlString 값
url.scheme         // "https"
url.host           // "ios-development.tistory.com"
url.path           // "/ios"
url.query          // "page=1&item2"

URLComponents, URLQueryItem

이름 그대로 URL 컴포넌트에 접근하여, query와 같은 값들을 쉽게 추가할수 있고 접근할 수 있는 방법이다.

  • 만약 URLComponents 없이 특정 query를 추가하거나 접근하려면 따로 문자열 처리가 필요하다.

query형을 가지고 있는 URLQueryItem 인스턴스를 만들어서 추가한다.

var components = URLComponents(string: "https://ios-development.tistory.com/ios?page=1&item=2")
let myQuery = URLQueryItem(name: "myKey", value: "myValue")
components?.queryItems?.append(myQuery)

URLComponents는 URL 인스턴스를 wrapping하고 있으므로 url 인스턴스에 접근 가능하다.

components?.url?.scheme // URL 인스턴트를 wrapping하고 있는 형태라 URL 인스턴스 접근 가능

queryItems 프로퍼티로 쿼리들에 접근이 가능하다.

components?.queryItems
// [{name "page", value "1"}, {name "item", value "2"}, {name "myKey", value "myValue"}]
components?.queryItems?.first?.value // 1

특정 path도 추가 가능하다.

components?.path.append("/myPath")

DeepLink 처리

딥링크를 처리할 때 보통 아래와 같은 URL을 사용하는데,

이때도 위에서 알아본 URLQueryItem을 가지고 모델링하여 사용하면 편리하다.

"my-app://home/sub?name=jake"

1. MyDeepLink 정리

  • 딥링크의 종류를 enum의 case로 나타내기 위해서 enum으로 정의한다.

    enum MyDeepLink {

    }

2. scheme 정의

  • enum 안에서는 stored property를 사용할 수 없으므로 static으로 선언한다.

  • 내부 init에서 해당 scheme을 사용할 것이므로 private으로 선언한다.

위 두가지를 고려하여 아래와 같이 선언

private static var scheme: String { return "my-app" }

3. 딥링크 케이스 정의

case home(name: String?)

4. host, path, queryItems 정의

var host: String {
  switch self {
  case .home:
    return "home"
  }
}

var path: String {
  switch self {
  case .home:
    return "/sub"
  }
}

var queryItems: [URLQueryItem] {
  switch self {
  case let .home(name):
    return [URLQueryItem(name: "name", value: name)]
  }
}

5. 초기화 할 때 사용할 메소드 준비

queryItems에서 key값에 대한 value값을 가져오는 함수 extension으로 정의

extension URL {
    
  func getValue(_ key: String) -> String? {
    URLComponents(url: self, resolvingAgainstBaseURL: true)?
      .queryItems?
      .first(where: { $0.name == key })?
      .value
  }
    
}

6. init 정의

switch문과 ~= 연산자를 사용한 패턴 매칭을 이용하여 초기화

(패턴 매칭 개념은 해당 여기 참고)

static func ~= (lhs: Self, rhs: URL) -> Bool {
  lhs.host == rhs.host && lhs.path == rhs.path
}

init?(urlString: String) {
  guard let url = URL(string: urlString), Self.scheme == url.scheme else { 
     return nil
  }
  
  switch url {
  case .home(name: nil):
    self = .home(name: url.getValue("name"))
  default:
    return nil
  }
}

참고 자료

https://ios-development.tistory.com/1014?category=899471