일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- iOS #Swift
- java #android #xml #sqlite
- iOS #대학생 #Swift
- 컴공 #Swift #대학생 #iOS
- 컴공 #자바스크립트 #스터디 #JS #대학생
- ios #boxoffice #영화진흥위원회 #swift #앱 #app #대학생
- 컴공 #Swift #대학생 #iOS #앱개발 #앱디자인
- node.js #npm #jest #test #웹테스트
- iOS #Swift #컴공 #공대생
- iOS #Swift #대학생 #개발 #코딩
- ios #swift #개발자 #apple
- iOS #Swift #컴공 #대학생
- web #socket #polling #소켓 #폴링 #네트워크 #웹
- 컴공 #Swift #대학생 #iOS #앱개발
- Today
- Total
평범한 컴공 대학생의 공부일지
영화 순위 Application 만들기(1) 본문
※이 iOS 카테고리의 글 들은 학교 강의와 과제를 기반으로 작성한 것입니다.※
1. ViewController, MyTableViewCell 코드
import UIKit
// 영화 이름 배열
let name = ["범죄도시4", "쿵푸팬더4", "스턴트맨", "포켓몬스터: 성도지방 이야기, 최종장", "남은 인생 10년", "파묘", "극장판 실바니안 패밀리 프레야의 선물", "꼬마참새 리차드: 신비한 보석 탐험대", "챌린저스", "고스트버스터즈: 오싹한 뉴욕"]
// 영화 데이터를 담을 구조체를 정의, Codable을 채택하여 JSON 파싱이 가능
struct MovieData : Codable {
let boxOfficeResult : BoxOfficeResult
}
struct BoxOfficeResult : Codable {
let dailyBoxOfficeList : [DailyBoxOfficeList]
}
struct DailyBoxOfficeList : Codable {
let movieNm : String // 영화 이름
let audiCnt : String // 해당 날짜의 관객 수
let audiAcc : String // 누적 관객 수
let rank : String // 박스 오피스 순위
}
// ViewController 클래스 정의
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var table: UITableView!
var movieData : MovieData? // 영화 데이터를 저장할 변수
// 박스 오피스 API URL. 실제 요청 시에는 날짜가 추가
var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=67a8c8861333b28525ac558c6a11a1b3&targetDt="
override func viewDidLoad() {
super.viewDidLoad()
// 테이블 뷰의 데이터 소스와 대리자(delegate)를 지정
table.dataSource = self
table.delegate = self
// API 호출을 위한 URL을 완성, 어제 날짜를 문자열로 추가
movieURL += makeYesterDayString()
// 데이터를 가져옵니다.
getData()
}
// 어제 날짜를 "YYYYMMdd" 형식의 문자열로 반환하는 함수
func makeYesterDayString() -> String {
let calendar = Calendar.current
if let yesterday = calendar.date(byAdding: .day, value: -1, to: Date()) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYYMMdd"
return dateFormatter.string(from: yesterday)
}
return "날짜 변환에 실패하였습니다."
}
// 데이터를 가져오는 함수
func getData(){
guard let url = URL(string: movieURL) else {return}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { data, response, error in
if error != nil { print(error!); return}
guard let JSONdata = data else { return }
print(JSONdata)
let decoder = JSONDecoder()
do{
// JSON 데이터를 MovieData 타입으로 디코딩합니다.
let decodedData = try decoder.decode(MovieData.self, from: JSONdata)
self.movieData = decodedData
// 메인 스레드에서 테이블 뷰를 새로고침합니다.
DispatchQueue.main.async {
self.table.reloadData()
}
} catch{
print(error)
}
}
task.resume()
}
// 테이블 뷰의 행의 수를 결정, 여기서는 고정된 값인 10을 반환
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
// 테이블 뷰의 각 셀을 구성하는 함수
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
// 영화 이름을 셀에 표시합니다.
cell.movieName.text =
movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm
return cell
}
// 테이블 뷰 섹션의 수를 결정, 여기서는 1개의 섹션만 사용
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 테이블 뷰의 행이 선택되었을 때의 동작을 정의하는 함수
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
import UIKit
class MyTableViewCell: UITableViewCell {
@IBOutlet weak var movieName: 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
}
}
2. Main Storyboard
3. 실행 화면
1. Stack View
UIStackView는 iOS 9에서 도입된 UI 컨트롤로, 자식 뷰를 수평 또는 수직의 단일 열로 자동으로 배열해주는 컨테이너 뷰입니다. 이를 통해 레이아웃을 구성하는 것이 훨씬 간결해지고, 복잡한 제약 조건을 관리하지 않아도 되는 장점이 있습니다.
UIStackView는 axis, alignment, distribution 및 spacing 등의 주요 속성을 가지고 있습니다.
- axis: 뷰의 배열 방향을 결정합니다. 수평(.horizontal) 또는 수직(.vertical)로 설정할 수 있습니다.
- alignment: 축에 수직한 방향에 대해 뷰를 어떻게 정렬할지 결정합니다. fill, leading, trailing, center 등 여러 옵션이 있습니다.
- distribution: 뷰의 크기를 어떻게 조정할지 결정합니다. fill, equalSpacing, equalCentering 등 다양한 옵션을 제공합니다.
- spacing: 뷰 사이의 간격을 지정합니다.
- Axis: 이 속성은 StackView의 방향을 결정합니다. .horizontal을 설정하면 StackView 내부의 뷰들이 수평으로 배열됩니다. 반면에, .vertical을 설정하면 뷰들이 수직으로 배열됩니다.
- Alignment: 이 속성은 StackView의 축과 수직인 방향으로 뷰들이 어떻게 배열될지를 결정합니다. 여기에는 다음과 같은 옵션이 있습니다.
- .fill: 뷰들이 StackView의 크기에 맞춰 전체 공간을 채우게 됩니다.
- .leading: 뷰들이 StackView의 leading edge에 맞춰 정렬됩니다.
- .trailing: 뷰들이 StackView의 trailing edge에 맞춰 정렬됩니다.
- .center: 뷰들이 StackView의 중심선에 맞춰 정렬됩니다.
- Distribution: 이 속성은 StackView 내부의 뷰들이 어떻게 분포될지를 결정합니다. 여기에는 다음과 같은 옵션이 있습니다.
- .fill: 뷰들이 가능한 모든 공간을 채우도록 확장됩니다.
- .fillEqually: 뷰들이 StackView의 크기에 맞춰 동일한 크기를 가지도록 조정됩니다.
- .fillProportionally: 뷰들의 크기가 뷰의 intrinsic content size에 비례하여 조정됩니다.
- .equalSpacing: 뷰들 사이의 간격이 동일하도록 조정됩니다.
- .equalCentering: 뷰들의 중심이 동일한 간격을 가지도록 조정됩니다.
2. Auto Layout
2-1. Alignment Contraints
아래 사진처럼 값을 주게 되면 Align AutoLayout이 설정됩니다. 음수(-)일 경우 왼쪽, 양수(+)일 경우 오른쪽입니다.
이를 통해 해상도가 다른 iPad, iPhone에서도 View가 깨지지 않고 정상적으로 작동하게됩니다.
2-2. Pin Tool
margin을 주어 입력한 값만큼 각 가장자리에서 떨어지게 됩니다. 아래처럼 10 입력시 각 가장자리로부터 10만큼 멀어지고 사이즈는 입력한 값 간격을 제외한 크기만큼 설정됩니다.
1. Size Inspector
Size Inspector는 Interface Builder에서 뷰의 크기, 위치, 오토 레이아웃 제약 조건 등을 설정하는데 사용되는 툴입니다. 이를 통해 더욱 정교하고 반응형 디자인을 구현할 수 있습니다.
1. 프레임 및 위치 설정
- Size Inspector를 사용하면 UI 요소의 너비, 높이, 좌표(X, Y)를 직접 입력하여 위치와 크기를 정확하게 조정할 수 있습니다. 또한, 앵커 포인트를 기준으로 요소를 조정하는 것도 가능합니다.
2. 오토 레이아웃 제약 조건
- UI 요소에 오토 레이아웃 제약 조건을 추가, 수정, 삭제할 수 있습니다. 이를 통해 다양한 화면 크기와 방향에 대응하는 반응형 디자인을 구현할 수 있습니다. 제약 조건에는 뷰의 크기, 위치, 간격 등이 포함됩니다.
3. 콘텐츠 크기 우선 순위
- 콘텐츠 크기 우선 순위를 설정하여, 화면 크기가 변할 때 어떤 뷰가 먼저 확장되거나 축소될지를 결정할 수 있습니다. 이는 복잡한 레이아웃에서 매우 유용한 기능입니다.
※ AutoLayout 주의사항
1. Intrinsic Content Size
개발하는 과정에서 개발자의 선택이 우선 순위가 높아야 하기 때문에 사이즈 우선순위가 높다.
1. Label 크기 조정
- Label의 텍스트가 잘릴 경우(...으로 출력되는 경우) 해결법
1. Lines를 0으로 지정 -> 1일 경우 1줄에 모두 출력한다는 의미
2. Autoshrink 설정
-> Fixed Font Size : 폰트 사이즈를 설정한 사이즈 그대로 유지
-> Minimum Font Scale : 폰트 스케일을 크기에 따라 자동 조정
-> Minimum Font Size : 폰트 사이즈를 크기에 따라 자동 조정
- 기존 프로젝트 수정하기(영화 등수, 누적/어제 관객 수 출력)
1. 누적 관객 수, 어제 관객 수 Label 추가 후 StackView 추가
2. 누적 관객 수, 어제 관객 수 Label -> MyTableViewCell에 Outlet으로 연결
3. ViewController의 tableView 함수 수정
import UIKit
let name = ["범죄도시4", "쿵푸팬더4", "스턴트맨", "포켓몬스터: 성도지방 이야기, 최종장", "남은 인생 10년", "파묘", "극장판 실바니안 패밀리 프레야의 선물", "꼬마참새 리차드: 신비한 보석 탐험대", "챌린저스", "고스트버스터즈: 오싹한 뉴욕"]
struct MovieData : Codable {
let boxOfficeResult : BoxOfficeResult
}
struct BoxOfficeResult : Codable {
let dailyBoxOfficeList : [DailyBoxOfficeList]
}
struct DailyBoxOfficeList : Codable {
let movieNm : String
let audiCnt : String
let audiAcc : String
let rank : String
}
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var table: UITableView!
var movieData : MovieData?
var movieURL = "https://kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=67a8c8861333b28525ac558c6a11a1b3&targetDt="
override func viewDidLoad() {
super.viewDidLoad()
table.dataSource = self
table.delegate = self
movieURL += makeYesterDayString()
getData()
}
func makeYesterDayString() -> String {
let calendar = Calendar.current
if let yesterday = calendar.date(byAdding: .day, value: -1, to: Date()) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYYMMdd"
return dateFormatter.string(from: yesterday)
}
return "날짜 변환에 실패하였습니다."
}
func getData(){
guard let url = URL(string: movieURL) else {return}
let session = URLSession(configuration: .default)
let task = session.dataTask(with: url) { data, response, error in
if error != nil { print(error!); return}
guard let JSONdata = data else { return }
print(JSONdata)
// let dataString = String(data: JSONdata, encoding: .utf8)
// print(dataString!)
let decoder = JSONDecoder()
do{
let decodedData = try decoder.decode(MovieData.self, from: JSONdata)
//print(decodedData.boxOfficeResult.dailyBoxOfficeList[0].movieNm)
//print(decodedData.boxOfficeResult.dailyBoxOfficeList[0].audiAcc)
self.movieData = decodedData
DispatchQueue.main.async {
self.table.reloadData()
}
} catch{
print(error)
}
}
task.resume()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
// 각 테이블 뷰 셀의 내용을 설정합니다.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// "myCell" 식별자를 가진 셀을 재사용하여 가져옵니다.
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
// 영화 데이터에서 현재 행(indexPath.row)에 해당하는 영화의 순위와 이름을 가져옵니다.
// 해당 데이터가 없을 경우 빈 셀을 반환합니다.
guard let mRank = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].rank else {return UITableViewCell()}
guard let mName = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].movieNm else {return UITableViewCell()}
// 셀에 영화 이름과 순위를 표시합니다.
cell.movieName.text = "[\(mRank)위 \(mName)]"
// 해당 영화의 어제 관객 수를 가져와서 콤마(,)를 포함한 숫자 형태로 변환 후 셀에 표시합니다.
if let aCnt = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiCnt {
let numF = NumberFormatter()
numF.numberStyle = .decimal
let aCount = Int(aCnt)!
let result = numF.string(for: aCount)!+"명"
cell.audiAccumulate.text = "어제 : \(result)"
}
// 해당 영화의 누적 관객 수를 가져와서 콤마(,)를 포함한 숫자 형태로 변환 후 셀에 표시합니다.
if let aAcc = movieData?.boxOfficeResult.dailyBoxOfficeList[indexPath.row].audiAcc {
let numF = NumberFormatter()
numF.numberStyle = .decimal
let aAcc1 = Int(aAcc)!
let result = numF.string(for: aAcc1)!+"명"
cell.audiCount.text = "누적 : \(result)"
}
return cell
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return "🍿박스오피스(영화진흥위원회제공:"+makeYesterDayString()+")🍿"
}
func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
return "by Taram"
}
// 테이블 뷰의 섹션 수를 결정합니다. 이 경우, 하나의 섹션만 사용하므로 1을 반환합니다.
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
// 테이블 뷰의 특정 행이 선택되었을 때 실행될 동작을 정의할 수 있습니다. 현재는 별도의 동작을 정의하지 않았습니다.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 여기에 행이 선택되었을 때의 동작을 추가할 수 있습니다.
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//print(indexPath.description)
}
}
1. 화면 전환 방법(Segue)
- Nevigation Controller
-> 추가 시 View Controller에 Navigation item이 추가 된 것을 확인
-> DetailViewController Swift 파일 생성 후 DetailViewController Scene과 class 연결
오늘 포스팅은 여기서 마치며 영화진흥위원회 어플리케이션을 계속 수정해 나가보겠습니다.
'iOS Swift' 카테고리의 다른 글
박스오피스 어플리케이션 정리 (0) | 2024.06.05 |
---|---|
영화 순위 Application 만들기 (2) (2) | 2024.05.23 |
iOS Swift 영화 순위 어플리케이션 (2) | 2024.04.18 |
iOS Swift 간단한 목록 Application 만들기 (1) | 2024.04.08 |
iOS Swift 문법 간단 복습 (0) | 2024.04.05 |