관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] URL 처리 방법 (URLComponents, URLQueryItem, DeepLink 모델링) 본문

iOS 응용 (swift)

[iOS - swift] URL 처리 방법 (URLComponents, URLQueryItem, DeepLink 모델링)

jake-kim 2022. 6. 21. 22:48

URL과 URI 구분

  • URI(Uniform Resource Identifier): 특정 리소스 식별자
  • URL(Uniform Resource Location): 특정 리소스 위치
    • URI의 방법중 하나가 URL

1번 - URI, 2번 - URL

URL의 구조

  • 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"
  • MyDeepLink 정리
    • 딥링크의 종류를 enum의 case로 나타내기 위해서 enum으로 정의
enum MyDeepLink {
}
  • scheme 정의
    • enum 안에서는 stored property를 사용할 수 없으므로 static으로 선언
    • 내부 init에서 해당 scheme을 사용할 것이므로 private으로 선언
private static var scheme: String { return "my-app" }
  • 딥링크 케이스 정의
case home(name: String?)
  • 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)]
  }
}
  • 초기화 할 때 사용할 메소드 준비
    • queryItems에서 key값에 대한 value값을 가져오는 함수 extension으로 정의
extension URL {
  func getValue(_ key: String) -> String? {
    URLComponents(url: self, resolvingAgainstBaseURL: true)?
      .queryItems?
      .first(where: { $0.name == key })?
      .value
  }
}
  • 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://github.com/JK0369/ExDeepLinkWithURL

Comments