楽天ブックスCD検索APIから画像、タイトル、アーティスト名、レーベル、説明文、曲名を取得

#今回の内容

<img width="150" alt="283F9428-C50F-4425-B63A-BDEA80A78844_1_201_a.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1466343/d3971d9f-6c5f-a468-af8c-d872ae5b1bba.jpeg">

#コード

##Model

```Swift:MusicDetailModel
struct MusicDetailModel{
    
    let mediumImageUrl:String?
    let title:String?
    let artistName:String?
    let label:String?
    let itemCaption:String?
    let playList:String?
}
```

```Swift:
import Alamofire
import SwiftyJSON

class AlamofireProcess{
    
    private var privateMediumImageUrl:String?
    private var privateTitle:String?
    private var privateArtistName:String?
    private var privateLabel:String?
    private var privateItemCaption:String?
    private var privatePlayList:String?
    
    private var getMusicDataArray = [MusicDetailModel]()
}

extension AlamofireProcess{
    
    public func getMusicData(searchKeyword:String?,completion: @escaping ([MusicDetailModel]?,Error?) -> Void){
        
        guard let keyword = searchKeyword else { return }
        
        let apikKey = "https://app.rakuten.co.jp/services/api/BooksCD/Search/20170404?format=json&artistName=\(keyword.urlEncoded)&applicationId=アプリID"
        
        AF.request(apikKey, method: .get, parameters: nil, encoding: JSONEncoding.default).responseJSON {[self] response in
            
            switch response.result{
                
            case .success:
                
                let detailData = JSON(response.data as Any)
                
                for dataCount in 0..<detailData["Items"].count{
                    
                    getDataNilCheck(checkMediumImageUrl: detailData["Items"][dataCount]["Item"]["mediumImageUrl"].string,
                                    checkTitle: detailData["Items"][dataCount]["Item"]["title"].string,
                                    checkArtistName: detailData["Items"][dataCount]["Item"]["artistName"].string,
                                    checkLabel: detailData["Items"][dataCount]["Item"]["label"].string,
                                    checkItemCaption: detailData["Items"][dataCount]["Item"]["itemCaption"].string,
                                    checkPlayList: detailData["Items"][dataCount]["Item"]["playList"].string)
                    
                    getMusicDataArray.append(MusicDetailModel(mediumImageUrl: privateMediumImageUrl,
                                                              title: privateTitle,
                                                              artistName: privateArtistName,
                                                              label: privateLabel,
                                                              itemCaption: privateItemCaption,
                                                              playList: privatePlayList))
                }
                
                completion(getMusicDataArray, nil)
                
            case .failure(let error):
            
                completion(nil, error)
            }
        }
    }
}

extension AlamofireProcess{
    
    private func getDataNilCheck(checkMediumImageUrl:String?,checkTitle:String?,checkArtistName:String?,checkLabel:String?,checkItemCaption:String?,checkPlayList:String?){
        
        if checkMediumImageUrl != nil{
            
            privateMediumImageUrl = checkMediumImageUrl
        }else{
            
            privateMediumImageUrl = "noSign"
        }
        
        
        if checkTitle != nil{
            
            privateTitle = checkTitle
        }else{
            
            privateTitle = "読み込みエラー"
        }
        
        if checkArtistName != nil{
            
            privateArtistName = checkArtistName
        }else{
            
            privateArtistName = "読み込みエラー"
        }
        
        if checkLabel != nil{
            
            privateLabel = checkLabel
        }else{
            
            privateLabel = "読み込みエラー"
        }
        
        if checkItemCaption != nil{
            
            privateItemCaption = checkItemCaption
        }else{
            
            privateItemCaption = "読み込みエラー"
        }
        
        if checkPlayList != nil{
            
            privatePlayList = checkPlayList
        }else{
            
            privatePlayList = "読み込みエラー"
        }  
    }

}

extension String{
    
    var urlEncoded:String{
        
        let charset = CharacterSet.alphanumerics.union(.init(charactersIn: "/?-._~"))
        let remove = removingPercentEncoding ?? self
        
        return remove.addingPercentEncoding(withAllowedCharacters: charset) ?? remove
    }
}
```

##View

<img width="150" alt="C813F240-8B4E-4811-B5E6-93B9CF643C72_4_5005_c.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1466343/0077d629-2a98-2bb3-1f0e-d186873ce804.jpeg">


```Swift:CollectionCustomCell
import UIKit

class CollectionCustomCell: UICollectionViewCell {

    @IBOutlet weak var mediumImageView: UIImageView!
    @IBOutlet weak var detailTextView: UITextView! 
    
    override func awakeFromNib() {
        super.awakeFromNib()
       
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
      
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        
        mediumImageView.image = UIImage(named: "")
        detailTextView.text = ""
    }
}
```

```Swift:MusicDetailViewController
import UIKit
import SDWebImage

class MusicDetailViewController: UIViewController {

    @IBOutlet weak var mediumImageView: UIImageView!
    @IBOutlet weak var playListView: UITableView!
    
    public var playlistContentsArray = [String]()
    
    public var imageURL:URL?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        mediumImageView.sd_setImage(with: imageURL, completed: nil)
        playListView.register(UINib(nibName: "TableViewCustomCell", bundle: nil), forCellReuseIdentifier: "MusicNameCell")
        playListView.dataSource = self
    }
   
}

extension MusicDetailViewController:UITableViewDataSource{
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        
        return "PlayList"
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        return playlistContentsArray.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "MusicNameCell", for: indexPath) as! TableViewCustomCell
        
        cell.musicNameLabel.text = playlistContentsArray[indexPath.row]
        
        return cell
    }
}
```

```Swift:TableViewCustomCell
import UIKit

class TableViewCustomCell: UITableViewCell {
    
    @IBOutlet weak var musicNameLabel: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
      
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        
        musicNameLabel.text = ""
    }
    
}
```

##Controller

* 取得した`playList`は曲名と曲名の間に`###`が存在する`String型`で取得されるので、`tableView`に表示する為に、`.components(separatedBy: "###")`を使用しています。

```Swift:ViewController
import UIKit
import SDWebImage

class ViewController: UIViewController {
    
    @IBOutlet weak var searchTextField: UITextField!
    @IBOutlet weak var searchButton: UIButton!
    @IBOutlet weak var resultCollectionView: UICollectionView!
    
    private let collectionViewLayout = UICollectionViewFlowLayout()
    
    private let alamofireProcess = AlamofireProcess()
    
    private var cellContentsArray = [MusicDetailModel]()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        resultCollectionView.register(UINib(nibName: "CollectionCustomCell", bundle: nil), forCellWithReuseIdentifier: "MusicDetailCell")
        resultCollectionView.delegate = self
        resultCollectionView.dataSource = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        collectionViewLayout.sectionInset = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
        resultCollectionView.collectionViewLayout = collectionViewLayout
    }

    @IBAction func artistNameSearch(_ sender: UIButton) {
        
        if searchTextField.text?.isEmpty != true{
            
            alamofireProcess.getMusicData(searchKeyword: searchTextField.text) { result, error in
                
                if error != nil{
                    
                    print(error.debugDescription)
                }
                
                DispatchQueue.main.asyncAfter(deadline: .now() + 5) {[self] in
                
                    cellContentsArray = result!
                    resultCollectionView.reloadData()
                }
            }
        }
    }
    
}

extension ViewController:UICollectionViewDelegate{
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        
        let musicDetailVC = MusicDetailViewController()
        musicDetailVC.modalPresentationStyle = .automatic
        musicDetailVC.playlistContentsArray = []
        musicDetailVC.playlistContentsArray = (cellContentsArray[indexPath.row].playList?.components(separatedBy: "###"))!
        musicDetailVC.imageURL = URL(string: cellContentsArray[indexPath.row].mediumImageUrl!)
        self.present(musicDetailVC, animated: true, completion: nil)
    }
}

extension ViewController:UICollectionViewDataSource{
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return cellContentsArray.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MusicDetailCell", for: indexPath) as! CollectionCustomCell
        
        cell.mediumImageView.sd_setImage(with: URL(string: cellContentsArray[indexPath.row].mediumImageUrl!))
        cell.detailTextView.text = """
                                   タイトル:
                                      \(cellContentsArray[indexPath.row].title ?? "読み込みエラー")
                                   
                                   アーティスト:
                                      \(cellContentsArray[indexPath.row].artistName ?? "読み込みエラー")
                                   
                                   レーベル:
                                      \(cellContentsArray[indexPath.row].label ?? "読み込みエラー")
                                   
                                   説明文:
                                      \(cellContentsArray[indexPath.row].itemCaption ?? "読み込みエラー")
                                   
                                   """
        
        return cell
    
    }
    
}

extension ViewController:UICollectionViewDelegateFlowLayout{
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        return CGSize(width: collectionView.frame.width / 2 - 10, height: collectionView.frame.height / 2 - 10)
    }
}
```

# 終わり
ご指摘、ご質問などありましたら、コメントまでお願い致します。