to do : GET 요청으로 음악 리스트를 검색하고, 30초 샘플을 다운받자.
아이튠즈 api 를 사용한다. (https://itunes.apple.com/search)
메인 뷰에 들어갈 VStack.
VStack{
TextField("search...", text: $searchText).padding()
Button(action: getSearchResults) {
Text("search")
}
List(searchResults, id: \.self) { result in
VStack{
SearchResultCell(artistName: result.artistName, trackName: result.trackName, albumName: result.albumName, releaseDate: result.releaseDate, previewUrl: result.previewUrl)
Button(action: {
self.startDownload(track: result)
}) {
Text("start download")
}
}
}
}
검색결과를 보여줄 행. 일단은 아티스트 이름과 곡제목, 앨범명, 발매날짜만 보여주는걸로 하자.
struct SearchResultCell : View {
var artistName: String
var trackName: String
var albumName: String
var releaseDate: String
var previewUrl: String
var body: some View {
VStack(alignment: .leading){
Text("Artist: \(artistName)")
Text("Track: \(trackName)")
Text("Album: \(albumName)")
Text("Release: \(releaseDate)")
}.padding()
}
}
검색결과를 담는 Model.
struct SearchResult: Hashable {
var artistName: String
var trackName: String
var albumName: String
var releaseDate: String
var previewUrl: String
}
아직 Button 을 눌렀을때 작동하는 함수를 구현하지 않았지만, View 는 다음과 같은 모양이 된다(iPad 7)
검색요청 함수와 다운로드 함수를 구현하자. URLSession 을 이용한다.
URLSession 과 관련된 글
https://o-o-wl.tistory.com/50
func getSearchResults() {
self.searchResults = []
guard var urlComponents = URLComponents(string: "https://itunes.apple.com/search") else { return }
urlComponents.query = "media=music&entity=song&term=\(searchText)"
guard let url = urlComponents.url else {return}
let task = URLSession.shared.dataTask(with: url) { data, response, error in
if let e = error {
NSLog("error: \(e.localizedDescription)")
return
}
DispatchQueue.main.async() {
do {
let object = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary
guard let jsonObject = object else {return}
let searchResults = jsonObject["results"] as! [NSDictionary]
searchResults.forEach { result in
let searchResult = SearchResult(artistName: result["artistName"] as! String, trackName: result["trackName"] as! String, albumName: result["collectionName"] as! String, releaseDate: result["releaseDate"] as! String, previewUrl: result["previewUrl"] as! String)
self.searchResults.append(searchResult)
}
} catch let e as NSError {
print("error: \(e.localizedDescription)")
}
}
}
task.resume()
}
func startDownload (track: SearchResult) {
guard let url = URL(string: track.previewUrl) else { return }
let task = URLSession.shared.downloadTask(with: url) { localURL, urlResponse, error in
if let localURL = localURL {
let documentsPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let destinationURL = documentsPath.appendingPathComponent(url.lastPathComponent)
// delete original copy
try? FileManager.default.removeItem(at: destinationURL)
// copy from temp to Document
do {
try FileManager.default.copyItem(at: localURL, to: destinationURL)
} catch let error {
print("Copy Error: \(error.localizedDescription)")
}
}
}
task.resume()
}
downloadTask 메소드를 사용하면, 파일이 tmp 폴더로 다운로드된뒤 얼마 안가 삭제된다. tmp 폴더에 다운로드한 파일을 복사해서 documents 폴더에 넣기 위해 FileManager 를 사용한다.
downloadTask 의 클로저에 들어간 completion handler 의 localURL은 파일이 저장되는 tmp 폴더의 위치를 의미한다.
print() 나 NSLog() 등으로 localURL 을 콘솔에 띄운뒤 나오는 주소를 복사한다.
파인더를 열어 cmd + shift + G 를 눌러서 복사한 url 을 입력하면 Xcode simulator 의 tmp 폴더 위치로 이동할 수 있다.
또는 디버그 콘솔에 po NSHomeDirectory() 를 입력하면 시뮬레이터의 파일시스템 주소가 뜨는데, Xcode 에 버그가 있는건지 안될때가 있었다
Xcode 에서 빌드를 하고, 음악을 검색해보자.
start download 가 적혀있는 행을 클릭하면, 해당하는 트랙의 30초 preview 를 다운받는다.
to do
다운로드 받은 음악들 UI 에 반영.
다운로드 받은 음악들 삭제할 수 있는 기능 추가.