iOS Swift 영화 순위 어플리케이션
※이 iOS 카테고리의 글 들은 학교 강의와 과제를 기반으로 작성한 것입니다.※
이번 포스트에서는 영화 순위 어플리케이션을 만들어보고 알아보겠습니다.
- ViewController
포스터 이미지, 영화 제목, 개봉 날짜가 포함된 영화 목록을 표시합니다.
1.기본 설정
- ViewController 클래스를 생성하고 UIViewController를 상속받습니다.
- UITableViewDelegate 및 UITableViewDataSource 프로토콜을 준수하도록 클래스를 구성
->이 두 프로토콜은 테이블 뷰의 데이터와 상호 작용을 관리하는 데 필수적
2. 데이터 준비
영화 목록을 표현하기 위해, 영화의 이미지 파일 이름, 제목, 개봉 날짜를 포함하는 배열을 준비합니다. 이 배열은 나중에 테이블 뷰에서 각 셀의 데이터로 사용됩니다.
3. 테이블 뷰 디자인
스토리보드를 사용하여 테이블 뷰와 셀을 디자인합니다. 테이블 뷰는 우리가 데이터를 표시할 캔버스이며, 각 셀은 영화 하나하나를 나타냅니다.
4. 테이블 뷰 구현
- 섹션과 행의 수 정의: numberOfRowsInSection 메서드를 통해 각 섹션에 표시될 행의 수를 정의합니다. 각 섹션마다 5개의 행을 가지도록 설정했습니다. 또한, numberOfSections 메서드를 통해 테이블 뷰의 섹션 수를 정의할 수 있으나, 대부분의 경우 하나의 섹션만을 사용하므로 이 메서드는 생략하거나 1을 반환하도록 합니다.
- 셀 구성: cellForRowAt 메서드에서는 테이블 뷰의 각 행에 해당하는 셀을 구성합니다. 재사용 가능한 셀을 요청하고, 준비한 데이터 배열에서 적절한 영화 정보를 가져와 셀에 표시합니다.
- 행 선택 처리: 사용자가 특정 행을 선택하면 didSelectRowAt 메서드가 호출됩니다. 이 예제에서는 선택된 행의 인덱스 경로를 콘솔에 출력하는 방식으로 간단히 처리했습니다.
import UIKit // UIKit 프레임워크를 임포트, iOS 앱의 사용자 인터페이스를 구성하고 관리하는 데 필요
// 영화 포스터 이미지 파일명, 영화 제목, 개봉일을 저장한 배열
let image = ["1.png", "2.png", "3.png", "4.png", "5.png"]
let name = ["[1] 쿵푸펜더4","[2] 파묘","[3] 남은인생10년","[4] 댓글부대","[5] 오멘: 저주의 시작",]
let open = ["2024-04-01","2024-02-11","2024-03-24","2024-04-18","2024-04-23"]
// ViewController 클래스는 UIViewController를 상속받으며, UITableViewDelegate와 UITableViewDataSource 프로토콜을 준수합니다.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var table: UITableView! // 스토리보드에서 연결한 UITableView의 아웃렛입니다.
// 테이블 뷰의 섹션당 행의 수를 정의 이 경우 각 섹션에는 5개의 행
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
// 테이블 뷰의 섹션 수를 정의 이 경우 총 5개의 섹션
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
// 각 행에 대한 셀을 구성, 여기서는 재사용 가능한 셀을 가져와서 영화 제목과 개봉일을 표시
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
cell.myLabel.text = name[indexPath.row]
cell.myOpen.text = open[indexPath.row]
print(indexPath.description)
return cell
}
// 특정 행이 선택되었을 때의 동작을 정의, 여기서는 선택된 행의 인덱스 경로를 콘솔에 출력
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.description)
}
// 뷰 컨트롤러의 뷰가 로드되었을 때 호출, 여기서 테이블 뷰의 데이터 소스와 델리게이트를 self로 설정
override func viewDidLoad() {
super.viewDidLoad()
table.dataSource = self
table.delegate = self
}
}
- TableViewController
1. UITableViewCell을 상속받아, 영화 제목과 개봉일을 표시하는 간단한 셀을 구현
2. @IBOutlet을 사용하여 UILabel로 myLabel과 myOpen을 정의합니다. 이 레이블들은 스토리보드에서 셀 디자인 시 연결할 수 있는 아웃렛으로, 영화 제목과 개봉일을 각각 표시하는 역할을 합니다.셀의 초기화 코드는 awakeFromNib 메서드 내에 작성할 수 있습니다.
3. awakeFromNib 메서드는 셀이 인터페이스 빌더로부터 로드될 때 호출되며, 여기에 초기화 로직을 구현 가능
4. 셀이 선택될 때의 동작은 setSelected(_:animated:) 메서드에서 구현 가능. 이 메서드는 셀의 선택 상태가 변경될 때 호출되며, 선택된 상태에 따라 셀의 UI를 변경하는 코드를 여기에 넣을 수 있습니다.
import UIKit
// MyTableViewCell 클래스 정의: UITableViewCell을 상속받는 커스텀 셀 클래스입니다.
class MyTableViewCell: UITableViewCell {
// myLabel: 영화 제목을 표시하는 레이블에 대한 아웃렛입니다.
@IBOutlet weak var myLabel: UILabel!
// myOpen: 영화 개봉일을 표시하는 레이블에 대한 아웃렛입니다.
@IBOutlet weak var myOpen: UILabel!
// awakeFromNib 메서드: 셀이 인터페이스 빌더로부터 로드될 때 호출됩니다. 초기화 코드를 넣을 수 있습니다.
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
// setSelected 메서드: 셀의 선택 상태가 변경될 때 호출됩니다.
// 이 메서드 내에서 셀이 선택되었을 때의 UI 변경 등을 설정할 수 있습니다.
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
- Main 디자인
1. Label 2개
2. TableView 1개
★ 뤼튼에게 물어본 내용
1. var x : Int? x = 10 if x != nil { print(x!) } else { print("nil") } 이 코드의 설명을 자세하게 주석으로 달아줘
// 옵셔널 정수형 변수 x를 선언합니다. 이 변수는 Int 타입의 값을 가질 수도 있고, 값이 없을 수도 있습니다(nil).
var x : Int?
// 변수 x에 정수값 10을 할당합니다. 이제 x는 nil이 아니며, Optional(10)을 포함합니다.
x = 10
// x가 nil이 아닌지 확인합니다. x가 nil이 아니라면, if 블록 내의 코드가 실행됩니다.
// x가 nil이라면, else 블록 내의 코드가 실행됩니다.
if x != nil {
// x가 nil이 아닌 경우, x의 값을 강제 언래핑하여 출력합니다.
// 강제 언래핑(!)은 옵셔널이 nil이 아님을 확신할 때 사용합니다.
// 여기서는 x가 nil이 아니라는 것을 이미 확인했으므로, 강제 언래핑하여 값 10을 출력합니다.
print(x!)
}
else {
// x가 nil인 경우, "nil" 문자열을 출력합니다.
// 이 블록은 x가 nil일 때 실행되지만, 위의 코드에서 x에 10을 할당했으므로 이 블록은 실행되지 않습니다.
print("nil")
}
2. var x : Int? x = 10 if let xx = x { print(x,xx) } else { print("nil") } 위 코드의 설명을 주석으로 상세히 달아줘
// 옵셔널 타입의 Int 변수 x를 선언합니다. 이는 Int 값 또는 nil을 가질 수 있습니다.
var x : Int?
// 변수 x에 정수 10을 할당합니다. 이로써 x는 nil이 아니게 됩니다.
x = 10
// if let 구문을 사용하여 옵셔널 x의 값을 안전하게 언래핑합니다.
// 이때, x가 nil이 아니라면(즉, 값이 있다면) 그 값을 새로운 상수 xx에 할당하고 if 블록 내부의 코드를 실행합니다.
if let xx = x { // 옵셔널 변수 x에 값(10)이 있으므로, 이 값을 언래핑해서 상수 xx에 대입하고 if문을 실행합니다.
// x와 언래핑된 값 xx를 출력합니다.
// x는 여전히 옵셔널이므로 "Optional(10)"을 출력하고, xx는 일반 Int 값이므로 "10"을 출력합니다.
print(x, xx)
}
else {
// x가 nil인 경우, 즉 값이 없는 경우 "nil"을 출력합니다.
// 이 예제에서는 x에 10이 할당되어 있으므로 이 블록은 실행되지 않습니다.
print("nil")
}
3. 옵셔널체이닝 예제 코드를 만들고 설명을 주석으로 달아줘
// 옵셔널 String 변수 x를 선언하고 "Hi"로 초기화합니다. 이는 x가 String 값을 가지거나 nil일 수 있음을 의미합니다.
var x : String? = "Hi"
// = "Hi" 부분을 제거하면 x는 nil 값을 가지게 됩니다.
// x를 옵셔널로 출력하며, Optional("Hi")와 같은 형태로 출력됩니다. x!를 통해 강제 언래핑을 하여 "Hi"를 출력합니다.
// 강제 언래핑은 옵셔널이 nil이 아님을 확신할 때 사용합니다. nil일 경우 런타임 에러가 발생합니다.
print(x, x!)
// if let을 사용하여 옵셔널 바인딩을 실시합니다. x가 nil이 아니면 그 값을 a에 할당하고 if문 내부를 실행합니다.
// 이 방식은 옵셔널이 nil인지 아닌지를 안전하게 확인하고 값을 추출하는 방법입니다.
if let a = x {
print(a)
}
// ?? 연산자를 사용하여 옵셔널 x가 nil일 경우 기본값인 ""(빈 문자열)을 c에 할당합니다.
// 이는 옵셔널이 nil일 때 기본값을 제공하는 간결한 방식입니다.
let c = x ?? ""
print(c)
// x!를 통해 강제 언래핑한 후, count 속성에 접근합니다. 이는 x가 nil이 아닐 때만 안전합니다.
// b의 타입(Int)과 값을 출력합니다.
let b = x!.count
print(type(of:b),b)
// 옵셔널 체이닝을 사용하여 x?.count를 통해 x의 count 속성에 안전하게 접근합니다.
// 이때 b1은 옵셔널 Int 타입이 됩니다. 옵셔널 체이닝은 옵셔널 내부의 속성이나 메소드에 접근할 때 사용되며,
// 해당 옵셔널이 nil이면 nil을 반환합니다.
let b1 = x?.count
// b1의 타입과 값을 출력합니다. b1은 옵셔널이므로 !를 사용하여 강제 언래핑을 해야 실제 값을 얻을 수 있습니다.
print(type(of:b1),b1, b1!)
4. Swift에서 ?과 !의 차이를 실행문과 선언문으로 나눠서 표로 작성해줘
5. 옵셔널 바인딩(if let)의 예제를 만들고 설명을 주석으로 달아줘
// 이 함수는 옵셔널 Int 값을 매개변수로 받아 처리하는 예시입니다.
func multiplyByTen(value: Int?) {
// 'if let' 구문을 사용하여 옵셔널 바인딩을 수행합니다.
// 이는 'value'가 nil이 아닌 경우, 즉 실제 값을 갖고 있는 경우에만
// 코드 블록 내부의 연산을 실행하게 됩니다.
if let number = value {
// 옵셔널 바인딩이 성공적으로 이루어졌으므로 'number'는
// 'value'의 실제 값으로 초기화되며, 이 값을 사용하여 연산을 수행합니다.
print(number * 10)
} else {
// 'value'가 nil일 경우, 즉 값이 없을 경우에는 else 블록이 실행됩니다.
// 여기서는 "Nil입니다"라는 메시지를 출력합니다.
print("Nil입니다")
}
}
// 함수를 호출하여 실제 동작을 확인합니다.
// 첫 번째 호출에서는 'value'로 3이 전달되며, 30이 출력됩니다.
multiplyByTen(value: 3)
// 두 번째 호출에서는 'value'로 nil이 전달되며, "Nil입니다"가 출력됩니다.
multiplyByTen(value: nil)
6. if let과 guard let else의 차이점을 예제로 설명해줘
// if let을 사용한 경우
if let number = value {
// 옵셔널이 nil이 아닌 경우 여기의 코드가 실행됩니다.
// 'number'는 이 블록 안에서만 유효한 지역 변수입니다.
print(number * 10)
} else {
// 옵셔널이 nil인 경우 여기의 코드가 실행됩니다.
print("Nil입니다")
}
// guard let을 사용한 경우
guard let number = value else {
// 옵셔널이 nil인 경우 여기의 코드가 실행되고, 함수 실행이 종료됩니다.
// 조기 출구(early exit)
return
}
// 옵셔널이 nil이 아닌 경우, 'number'는 이후 코드에서도 사용할 수 있습니다.
print(number*10)
- if let과 guard let else의 차이점
1) 범위(Scope) 차이: if let을 사용하면 바인딩된 변수(number)는 if 블록 안에서만 유효합니다. 반면, guard let을 사용하면 바인딩된 변수를 guard문 이후의 코드에서도 계속 사용할 수 있습니다.
2) 코드 흐름(Flow): guard let은 주로 함수의 시작 부분에 조건을 빨리 체크하고, 조건이 충족되지 않을 경우 빠르게 함수에서 빠져나가기 위해 사용됩니다. 이는 코드의 중첩을 줄이고, 보다 선형적인 코드 흐름을 유지할 수 있게 해줍니다.
3) 옵셔널 처리 의도: if let은 옵셔널 값이 nil이 아닐 때 특정 작업을 수행하고자 할 때 사용합니다. guard let은 옵셔널 값이 nil인 경우에 대한 처리(대부분 함수 종료나 에러 처리)를 먼저 명시하고, 그 외의 경우에 대한 로직을 계속 진행하고자 할 때 사용합니다.
6. failable initializer 설명을 예제 코드의 주석으로 달아줘
// 'Man' 클래스 선언
class Man{
// 'age'와 'weight' 프로퍼티 선언 및 기본값 할당
var age : Int = 1
var weight : Double = 3.5
// 'display' 메서드 선언: 객체의 'age'와 'weight'를 출력
func display(){
print("나이=\(age), 몸무게=\(weight)")
}
// 실패 가능한 생성자 (failable initializer) 선언
// 'age'와 'weight'를 파라미터로 받아 객체를 초기화.
// 이 생성자는 실패 가능성을 내포하고 있어, 초기화 과정에서 문제가 발생하면 nil을 반환할 수 있음.
init?(age: Int, weight : Double){
self.age = age
self.weight = weight
}
}
// 'Man' 타입의 'kim' 변수를 옵셔널로 선언하고, 'Man' 객체를 생성하여 할당.
// 생성자가 실패 가능한 생성자이므로 결과는 옵셔널 타입임.
var kim : Man? = Man(age:10, weight:20.5)
// 옵셔널 바인딩을 사용하여 'kim'이 nil이 아닌지 확인하고,
// nil이 아닐 경우 'kim1'이라는 상수에 할당 후 'display' 메서드 호출.
// 이는 'kim' 객체가 성공적으로 생성되었는지를 확인하고, 생성되었다면 해당 객체의 'display' 메서드를 호출함.
if let kim1 = kim {
kim1.display()
}
// 또 다른 방법
//if let kim = Man(age:10, weight:20.5) {
// kim.display()
//}