swift tabbar controller tableview 영화목록 영화관 스위프트 테이블뷰 탭바 컨트롤러



//

//  MovieCell.swift

//  MyMovieChart

//

//  Created by stayfoolish on 29/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class MovieCell: UITableViewCell {

    

    @IBOutlet var title: UILabel!

    @IBOutlet var desc: UILabel!

    @IBOutlet var opendate: UILabel!

    @IBOutlet var rating: UILabel!

    @IBOutlet var thumbnail: UIImageView!

    

}


//

//  MovieVO.swift

//  MyMovieChart

//

//  Created by stayfoolish on 28/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import Foundation

import UIKit


class MovieVO {

    var thumbnail: String? // 영화 섬네일 이미지 주소

    var title: String? // 영화 제목

    var description: String? // 영화 설명

    var detail: String? // 상세정보

    var opendate: String? // 개봉일

    var rating: Double? // 평점

    

    // 영호 썸네일 이미지를 담을 UIImage 객체를 추가한다.

    var thumbnailImage: UIImage?

}


//

//  ListViewController.swift

//  MyMovieChart

//

//  Created by stayfoolish on 28/10/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class ListViewController: UITableViewController {

    

    @IBOutlet var moreBtn: UIButton!

    

    /*

    // 튜플 아이템으로 구성된 데이터 세트

    var dataset = [

        ("다크 나이트","영웅물에 철학에 음악까지 더해져 예술이 되다.","2008-09-04",8.95,"darknight.jpg"),

        ("호우시절","때를 알고 내리는 좋은 비","2009-10-08",7.31,"rain.jpg"),

        ("말할 수 없는 비밀","여기서 너까지 다섯 걸음","2015-05-07",9.19,"secret.jpg")

    ]

    */

    

    // 현재까지 읽어온 데이터의 페이지 정보

    var page = 1

    

    // 테이블 뷰를 구성할 리스트 데이터

    lazy var list: [MovieVO] = {

        var datalist = [MovieVO]()

       /*

        for (title, desc, opendate, rating, thumbnail) in self.dataset {

            let mvo = MovieVO()

            mvo.title = title

            mvo.description = desc

            mvo.opendate = opendate

            mvo.rating = rating

            mvo.thumbnail = thumbnail

            

            datalist.append(mvo)

        }

       */

        return datalist

    }()



    @IBAction func more(_ sender: UIButton) {

    // 0) 현재 페이지 값에 1을 추가한다.

    self.page += 1

    

    // 영화차트 API를 호출한다.

    self.callMovieAPI()

        

        

    // 데이터를 다시 읽어오도록 테이블 뷰를 갱신한다.

    self.tableView.reloadData()

    }

    

    

    // 뷰가 처음 메모리에 로드될 때 호출되는 메소드

    override func viewDidLoad() {

        // 영화차트 API를 호출한다.

        self.callMovieAPI()


    }

    

    func callMovieAPI() {

        // 1) 호핀 API를 호출을 위한 URI를 생성

//        let url = "http://swiftapi.rubypaper.co.kr:2029/hoppin/movies?version=1&page=\(self.page)&count=10&genreId=&order=releasedateasc"

        let url = "http://swiftapi.rubypaper.co.kr:2029/hoppin/movies?version=1&page=\(self.page)&count=30&genreId=&order=releasedateasc"

        

        let apiURL: URL! = URL(string: url)

        

        // 2) REST API를 호출

        let apidata = try! Data(contentsOf: apiURL)

        

        // 3) 데이터 전송 결과를 로그로 출력 (반드시 필요한 코드는 아님)

        let log = NSString(data: apidata, encoding: String.Encoding.utf8.rawValue) ?? "데이터가 없습니다"

        NSLog("API Result=\( log )")

        

        // 4) JSON 객체를 파싱하여 NSDictionary 객체로 받음

        do {

            let apiDictionary = try JSONSerialization.jsonObject(with: apidata, options: []) as! NSDictionary

            

            // 5) 데이터 구조에 따라 차례대로 캐스팅하며 읽어온다.

            let hoppin = apiDictionary["hoppin"] as! NSDictionary

            let movies = hoppin["movies"] as! NSDictionary

            let movie = movies["movie"] as! NSArray

            

            // 6) Iterator 처리를 하면서 API 데이터 MovieVO 객체에 저장한다.

            for row in movie {

                // 순회 상수를 NSDictionary 타입으로 캐스팅

                let r = row as! NSDictionary

                

                // 테이블 뷰 리스트를 구성할 데이터 형식

                let mvo = MovieVO()

                

                // movie 배열의 각 데이터를 mvo 상수의 속성에 대입

                mvo.title = r["title"] as? String

                mvo.description = r["genreNames"] as? String

                mvo.thumbnail = r["thumbnailImage"] as? String

                mvo.detail = r["linkUrl"] as? String

                mvo.rating = ((r["ratingAverage"] as! NSString).doubleValue)

                

                // 웹상에 있는 이미지를 읽어와 UIImage 객체로 설정

                let url: URL! = URL(string: mvo.thumbnail!)

                let imageData = try! Data(contentsOf: url)

                mvo.thumbnailImage = UIImage(data:imageData)

                

                

                // list 배열에 추가

                self.list.append(mvo)

                

                // 7) 전체 데이터 카우트를 얻는다.

                let totalCount = (hoppin["totalCount"] as? NSString)!.integerValue

                

                // 8) totalCount가 읽어온 데이터 크기와 같거나 클 경우 더보기 버튼을 막는다.

                if (self.list.count >= totalCount){

                    self.moreBtn.isHidden = true

                }

            }

        }catch { NSLog("Parse Error!!")}

    }

    

    func getThumnailImage(_ index: Int) -> UIImage {

        // 인자값으로 받은 인덱스를 기반으로 해당하는 배열 데이터를 읽어옴

        let mvo = self.list[index]

        

        // 메모이제이션 : 저장된 이미지가 있으면 그것을 반환하고, 없을 경우 내려받아 저장한 후 반환

        if let savedImage = mvo.thumbnailImage {

            return savedImage

        }else {

            let url: URL! = URL(string: mvo.thumbnail!)

            let imageData = try! Data(contentsOf: url)

            mvo.thumbnailImage = UIImage(data:imageData) // UIImage를 MovieVO 객체에 우선 저장

            

            return mvo.thumbnailImage! // 저장된 이미지를 반환

        }

        

        

    }


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

            return self.list.count

    }

    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // 주어진 행에 맞는 데이터 소스를 읽어온다.

        let row = self.list[indexPath.row]

        

        // 로그 출력

        NSLog("제목:\(row.title!), 호출된 행번호:\(indexPath.row)")

        

        // 테이블 셀 객체를 직접 생성하는 대신 큐로부터 가져옴

        // as! UITableViewCell => as! MovieCell 로 캐스팅 타입 변경

        let cell = tableView.dequeueReusableCell(withIdentifier: "ListCell") as! MovieCell

        

        // 데이터 소스에 저장된 값을 각 아울렛 변수에 할당

        cell.title?.text = row.title

        cell.desc?.text = row.description

        cell.opendate?.text = row.opendate

        cell.rating?.text = "\(row.rating!)"


        /*

        // 섬네일 경로를 인자값으로 하는 URL 객체를 생성

        let url: URL! = URL(string: row.thumbnail!)

        

        // 이미지를 읽어와 Data 객체에 저장

        let imageData = try! Data(contentsOf: url)

        

        // UIImage 객체를 생성하여 아울렛 변수의 image 속성에 대입

        cell.thumbnail.image = UIImage(data: imageData)

        */

        

        /*

        // 이미지 객체를 대입힌다.

        cell.thumbnail.image = row.thumbnailImage

        */

        

        // 비동기 방식으로 섬네일 이미지를 읽어옴

        DispatchQueue.main.async(execute: {

            NSLog("비동기 방식으로 실행되는 부분입니다")

            cell.thumbnail.image = self.getThumnailImage(indexPath.row)

        })

 

        NSLog("메소드 실행을 종료하고 셀을 리턴합니다.")

        // 셀 객체를 반환

        return cell

    }

    

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        NSLog("선택된 행은 \(indexPath.row) 번째 행입니다.")

    }

}


//

//  TheaterCell.swift

//  MyMovieChart

//

//  Created by stayfoolish on 27/11/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class TheaterCell: UITableViewCell {


    

    @IBOutlet var name: UILabel! // 상영관명

    @IBOutlet var tel: UILabel! // 연락처

    @IBOutlet var addr: UILabel! // 주소

    

    

    override func awakeFromNib() {

        super.awakeFromNib()

        // Initialization code

    }


    override func setSelected(_ selected: Bool, animated: Bool) {

        super.setSelected(selected, animated: animated)


        // Configure the view for the selected state

    }


}


//

//  TheaterListController.swift

//  MyMovieChart

//

//  Created by stayfoolish on 27/11/2018.

//  Copyright © 2018 stayfoolish. All rights reserved.

//


import UIKit


class TheaterListController: UITableViewController {


    // API를 통해 불러온 데이터를 저장할 배열 변수

    var list = [NSDictionary]()

    

    // 읽어올 데이터의 시작위치

    var startPoint = 0

    

    override func viewDidLoad() {

        super.viewDidLoad()

        self.callTheaterAPI()

    }

    

    func callTheaterAPI(){

        // URL을 구성하기 위한 상수값을 선언한다.

        let requestURI = "http://swiftapi.rubypaper.co.kr:2029/theater/list" // API 요청 주소

        

        let sList = 100 // 불러올 데이터 갯수

        let type = "json" // 데이터 형식

        

        // 인자값을 모아 URL 객체로 정의한다.

        let urlObj = URL(string: "\(requestURI)?s_page=\(self.startPoint)&s_list=\(sList)&type=\(type)")

        

        do {

            // NSString 객체를 이용하여 API를 호출하고 그 결과값을 인코딩된 문자열로 받아온다.

            let stringdata = try NSString(contentsOf: urlObj!, encoding: 0x80_000_422)

            

            // 문자열로 받은 데이터를 UTF-8로 인코딩 처리한 Data로 변환한다.

            let encdata = stringdata.data(using: String.Encoding.utf8.rawValue)

            do {

                // Data 객체를 파싱하여 NSArray 객체로 변환한다.

                let apiArray = try JSONSerialization.jsonObject(with: encdata!, options: []) as? NSArray

                

                // 읽어온 데이터를 순회하면서 self.list 배열에 추가한다.

                for obj in apiArray! {

                    self.list.append(obj as! NSDictionary)

                }

            }catch {

                // 경고창 형식으로 오류 메세지를 표시해준다.

                let alert = UIAlertController(title: "실패", message: "데이터 분석이 실패하였습니다.", preferredStyle: .alert)

                alert.addAction(UIAlertAction(title: "확인", style: .cancel))

                self.present(alert, animated: false)

            }

            // 읽어와야 할 다음 페이지의 데이터 시작 위치를 구해 저장해둔다.

            self.startPoint += sList

        }catch {

            // 경고창 형식으로 오류 메세지를 표시해준다.

            let alert = UIAlertController(title: "실패", message: "데이터를 불러오는데 실패하였습니다.", preferredStyle: .alert)

            

            alert.addAction(UIAlertAction(title: "확인", style: .cancel ))

            self.present(alert, animated: false)

        }

    }


    // MARK: - Table view data source




    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

        // #warning Incomplete implementation, return the number of rows

        return self.list.count

    }


    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        // self.list 배열에서 행에 맞는 데이터를 꺼냄

        let obj = self.list[indexPath.row]

        

        // 재사용 큐로부터 tCell 식별자를 맞는 셀 객체를 전달받음

        let cell = tableView.dequeueReusableCell(withIdentifier: "tCell", for: indexPath) as! TheaterCell

        

        cell.name?.text = obj["상영관명"] as? String

        cell.tel?.text = obj["연락처"] as? String

        cell.addr?.text = obj["소재지도로명주소"] as? String

        

        return cell

    }

    


    /*

    // Override to support conditional editing of the table view.

    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {

        // Return false if you do not want the specified item to be editable.

        return true

    }

    */


    /*

    // Override to support editing the table view.

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {

        if editingStyle == .delete {

            // Delete the row from the data source

            tableView.deleteRows(at: [indexPath], with: .fade)

        } else if editingStyle == .insert {

            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view

        }    

    }

    */


    /*

    // Override to support rearranging the table view.

    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {


    }

    */


    /*

    // Override to support conditional rearranging of the table view.

    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {

        // Return false if you do not want the item to be re-orderable.

        return true

    }

    */


    /*

    // MARK: - Navigation


    // In a storyboard-based application, you will often want to do a little preparation before navigation

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // Get the new view controller using segue.destination.

        // Pass the selected object to the new view controller.

    }

    */


}








+ Recent posts