졸업 작품을 진행하면서, 서버와 통신하는 작업을 위해 swift에서의 네트워킹에 대해 찾아보았다.
앱 개발에서 가장 중요한 것 중 하나인 네트워킹, 네트워킹을 위해서는 swift에서 기본적으로 제공해주는 URLSession이 있다는 것을 알게 되었다.
URLSession을 공부하기에 앞서, 먼저 swift에서 URL이 무엇이고, 이 URL에 대한 다른 기능들이 무엇이 있는지 먼저 공부하기로 하였다.
가장 먼저 알게된 것은 URLComponents였다.
오늘은 URL과 URLComponents에 대하여 내가 공부하고 정리한 내용들을 작성할 생각이다.
URL은 Uniform Resource Locater의 약자로, Apple에서는 원격 서버의 항목이나 로컬 파일의 경로와 같은 리소스의 위치를 식별하는 값
이라고 설명한다.
웹 페이지를 찾기 위한 주소 또는 로컬 파일의 경로
라고 이해하면 된다.
웹에서는 주소창에 URL을 입력하면, 해당 URL을 통해 웹 페이지에 대한 정보를 받아오고, 그 페이지에서 상호작용을 통해 다른 페이지(URL)로 이동하거나 다양한 작업들을 할 수 있다.
앱에서는 URL을 통해 서버와 통신하며 데이터를 주고 받을 뿐만 아니라, 크롤링과 같이 웹 페이지를 이용하여 다양한 기능들을 활용할 수 있다. 또한, 앱 내에서 URL을 통해 파일이나 폴더에 접근, 생성, 삭제를 할 수 있다.
오늘은 URL을 통해 서버와 통신하는 것이 아닌, URL의 구성에 대해 알아보려고 한다.
이 외에도 많은 구성 요소들이 있지만, 6개의 구성 요소에 대한 예시만 코드를 이용하여 어떤 결과가 나오는지 보여주겠다.
let urlString = "https://github.com/vhzkclq0705?tab=repositories"
let url = URL(string: urlString)!
url.absoluteURL // https://github.com/vhzkclq0705?tab=repositories
url.scheme // "https"
url.host // "github.com"
url.path // "/vhzkclq0705"
url.query // "tab=repositories"
url.baseURL // nil
주소는 내 깃허브 repositories 주소이다.
절대주소이기 때문에, basURL의 값이 nil인 것을 알 수 있다.
상대주소로 나타내기 위해서는 URL에서 relativeTo:
라는 옵션을 사용하면 된다.
let baseURL = URL(string: "https://github.com")!
let relativeURL = URL(string: "vhzkclq0705?tab=repositories", relativeTo: baseURL)!
relativeURL.absoluteURL // https://github.com/vhzkclq0705?tab=repositories
relativeURL.scheme // "https"
relativeURL.host // "github.com"
relativeURL.path // "/vhzkclq0705"
relativeURL.query // "tab=repositories"
relativeURL.baseURL! // https://github.com
나머지는 절대주소와 동일하나, baseURL이 nil이 아니다.
URL에 대한 내용은 그렇게 많지 않다. 보통 URL을 이용하여 네트워킹에 사용되기 때문에, URL 값 자체만으로는 네트워킹이나 파일 관련을 제외하고는 사용할 일이 거의 없을 것이다.
URL을 더 효율적으로 사용하기 위한 URLComponents를 더 많이 사용할 것 같다.
URLComponents는 구성 요소들로부터 URL을 구문분석(?)하고 구성하는 구조
이다.
URL과 URLComponents는 같은 값을 가질 수 있지만, 다른 타입이다.
URL을 URL(string:)으로 작성한다면, URLComponents는 URLComponents(string:)으로 작성할 수 있다.
URL과 URLComponents의 값은 동일하기 때문에 URLComponents로도 파일의 경로나 웹페이지 주소로 이동할 수 있다.
URLComponents또한 URL처럼 다양한 구성 요소들을 가지고 있는데, 차이점은 이 구성 요소들을 관리할 수 있다는 점이다.
위에 relativeURL.query를 보면 "tab=repositories"라는 쿼리가 반환되는데, URL의 쿼리가 여러개가 있을 경우에는 "tab=repositories&q=" 와 같이 &(and) 를 포함한 여러 개의 쿼리들이 같이 반환된다.
URLComponents는 이 여러개의 쿼리들을 queryItem 타입을 통해 각 쿼리를 따로 반환시키거나 추가, 수정을 할 수도 있다.
URLComponents에서 "tab=repositories" 라는 쿼리는 "tab" 이라는 name
값과 "repositories" 라는 value
값을 가진 하나의 queryItem이다.
(name과 value는 모두 String 타입이다.)
queryItem은 [queryItem] 이라는 queryItem의 배열의 각 요소들로 나타내진다.
아래 예시를 통해, URLComponents에서 queryItem이 어떻게 표현되는지 알아보도록 하자.
let urlString = "https://github.com/vhzkclq0705?tab=repositories&q=&type=&language=&sort="
let components = URLComponents(string: urlString)!
let items = components.queryItems ?? []
// [{name "tab", value "repositories"}, {name "q", value ""}, {name "type", value ""}, {name "language", value ""}, {name "sort", value ""}]
for item in items {
print("name: \(item.name)")
print("value: \(item.value)")
}
// --print 결과--
// name: tab
// value: Optional("repositories")
// name: q
// value: Optional("")
// name: type
// value: Optional("")
// name: language
// value: Optional("")
// name: sort
// value: Optional("")
다양한 쿼리의 값을 위해 repositories에서 All타입 정렬을 한 URL을 사용했다.
components의 queryItem들을 items 변수에 담아두면, 각 queryItem들이 name과 value형태로 나뉘어져 배열에 들어 있는 것을 볼 수 있다.
value값이 없으면 빈 문자열로 반환된다.
그래서 쿼리의 값을 얻어서 어디에 쓰냐?
URLComponents를 통해 queryItem을 각각 얻어올 수도 있지만, 반대로 queryItem을 추가하여 새로운 URLComponents를 만들 수도 있다.
var components = URLComponents(string: "https://github.com/vhzkclq0705")!
let tab = URLQueryItem(name: "tab", value: "repositories")
let q = URLQueryItem(name: "q", value: "")
let type = URLQueryItem(name: "type", value: "")
let language = URLQueryItem(name: "language", value: "")
let sort = URLQueryItem(name: "sort", value: "")
components.queryItems = [tab, q, type, language, sort]
components.url!
// https://github.com/vhzkclq0705?tab=repositories&q=&type=&language=&sort=
쿼리 앞부분만 있는 URL에서 queryItem들을 추가하여 위에서 사용한 URL을 만들어 주었다.
이렇듯 도메인 값에서 쿼리들을 추가하여 원하는 URL을 얻고 싶은 경우 URLComponents를 사용할 수 있다.
URLComponents는 이 외에도 다양하게 활용할 수 있다.
URL은 기본적으로 영어로 작성 되어있고, 한글(영어가 아닌 언어) 또는 띄어쓰기가 포함되어 있으면 URL을 제대로 인식할 수 없다.
제대로 인식하기 위해서는 한글이나 띄어쓰기를 URL 인코딩 해주어야 한다.
URLComponents는 이 URL 인코딩도 알아서 해준다.
멜론 사이트를 예시로 설명하겠다.
멜론 사이트에서 "아이유"를 검색하면 다음과 같은 페이지가 나타난다.
URL을 보면 어? 한글이 있는데 제대로 페이지 나오는데? 라고 생각할 수 있다.
하지만, 이는 크롬에서 자동적으로 URL 인코딩이 되기 때문에 그렇다.
let urlString = "https://www.melon.com/search/total/index.htm?q=아이유§ion=&searchGnbYn=Y&kkoSpl=Y&kkoDpType=&mwkLogType=T"
let url = URL(string: url) // error!
swift에서 같은 URL을 사용하면, 한글인 "아이유"가 제대로 인식되지 않아서 에러가 발생한다. swift에서는 URL 인코딩을 따로 해주지 않기 때문이다.
이를 해결하는 방법은 urlString 이나 한글을을 따로 빼서 URL 인코딩을 해주고 URL로 다시 변환시켜 주는 방법도 있지만, URLComponents를 사용할 수도 있다.
let url = "https://www.melon.com/search/total/index.htm?"
var components = URLComponents(string: url)!
let q = URLQueryItem(name: "q", value: "아이유")
let section = URLQueryItem(name: "section", value: "")
let searchGnbYn = URLQueryItem(name: "searchGnbYn", value: "Y")
let kkoSpl = URLQueryItem(name: "kkoSpl", value: "Y")
let kkoDpType = URLQueryItem(name: "kkoDpType", value: "")
let mwLogType = URLQueryItem(name: "mwLogType", value: "T")
components.queryItems = [q, section, searchGnbYn, kkoSpl, kkoDpType, mwLogType]
components.url!
// https://www.melon.com/search/total/index.htm?q=%EC%95%84%EC%9D%B4%EC%9C%A0§ion=&searchGnbYn=Y&kkoSpl=Y&kkoDpType=&mwLogType=T
URLQueryItem에서는 한글을 그대로 입력하여도 정상적으로 실행이 된다.
하지만 반환된 값을 보면 뭔가 다른 부분이 보인다.
"아이유" 대신 “%EC%95%84%EC%9D%B4%EC%9C%A0” 라는 이상한 값이 들어가 있다.
이 이상한 값이 바로 "아이유"를 URL 인코딩한 값이다.
URLComponents에서는 자동적으로 URL 인코딩을 해준다는 것을 알 수 있다.
원래 알고 있던 URL
https://www.melon.com/search/total/index.htm?q=아이유§ion=&searchGnbYn=Y&kkoSpl=Y&kkoDpType=&mwLogType=T
두 URL은 모두 같은 페이지가 나온다.
오늘은 이렇게 URL과 URLComponents에 대해 알아보았습니다!
졸업 작품을 하면서 크롤링을 할 때, 기본 URL 값에 추가해줄 String값을 매개 변수로 받아서 따로 URL 인코딩을 시켜주었는데, 이런 방법이 있다는 것을 이번 공부에서 알게 되었네요!!
다음에는 URLSession을 공부하여 글을 작성할 예정입니다!