앱 소스 복습
import UIKit // UIKit 프레임워크를 임포트함. iOS UI 구성 요소를 사용하기 위해 필요함.
// 영화 포스터 이미지 파일 이름을 저장하는 배열
let image = ["1.png", "2.png", "3.png", "4.png", "5.png"]
// 영화 제목을 저장하는 배열
let name = ["쿵푸팬더4", "파묘", "남은 인생 10년", "댓글부대", "오멘: 저주의 시작"]
// 영화 판매 금액을 저장하는 배열
let salesAmt = [3974644920, 702489712, 364066322, 333249472, 131334039]
// ViewController 클래스 선언. UIViewController를 상속받고 UITableViewDelegate, UITableViewDataSource 프로토콜을 채택함
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
// 스토리보드에서 연결된 UITableView의 아웃렛 변수
@IBOutlet weak var table: UITableView!
// 테이블 뷰의 섹션 수를 정의함. 여기서는 5개의 섹션을 반환함
func numberOfSections(in tableView: UITableView) -> Int {
return 5
}
// 각 섹션의 행 수를 정의함. 여기서는 각 섹션마다 5개의 행을 반환함
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
// 테이블 뷰의 각 행에 대한 셀을 구성함
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// "myCell" 식별자를 가진 재사용 가능한 셀을 가져오고 MyTableViewCell 타입으로 캐스팅함
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell",
for: indexPath) as! MyTableViewCell
// 셀의 myLabel에 영화 제목을 설정함
cell.myLabel.text = name[indexPath.row]
// 셀의 salesAmt에 영화 판매 금액을 설정함. 금액은 문자열로 변환됨
cell.salesAmt.text = "\(salesAmt[indexPath.row])"
return cell // 구성된 셀을 반환함
}
// 테이블 뷰의 특정 행이 선택되었을 때 호출됨
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// 선택된 indexPath의 설명을 콘솔에 출력함
print(indexPath.description)
}
// 뷰 컨트롤러의 뷰가 메모리에 로드된 후 호출됨
override func viewDidLoad() {
super.viewDidLoad()
// 테이블 뷰의 delegate와 dataSource를 현재 뷰 컨트롤러 인스턴스로 설정함
table.delegate = self
table.dataSource = self
}
}
ㄴ 테이블 뷰를 이용한 박스오피스 순위 앱 코드이다.
import UIKit
// UITableViewCell을 상속받는 MyTableViewCell 커스텀 클래스 정의
class MyTableViewCell: UITableViewCell {
// 스토리보드에서 셀의 레이블을 연결하기 위한 IBOutlet 변수들
@IBOutlet weak var myLabel: UILabel! // 영화 제목을 표시할 레이블
@IBOutlet weak var salesAmt: UILabel! // 영화의 판매액을 표시할 레이블
}
문법 복습
var x : Int? // 옵셔널 정수형 변수 x 선언 / 선언문에서 자료형 다음에 ?를 쓰면 옵셔널 변수 선언
print(x) // 옵셔널 변수는 초기화하지 않으면 nil로 초기화 / nil은 값이 없다는 의미
var y : Int = 0
x = 10 // 주석처리하면? / 옵셔널 변수는 값을 대입해도 Optional() 안에 감싸진다. (wrapping)
print(x) // Optional(10)
print(x!) // forced unwrapping해서 10이 나옴 / 실행문에서 변수 다음에 !를 하면 옵셔널을 푼다는 의미
print(y)
x = x! + 2 // 가능?
print(x)
y = x! // 가능?
print(y)
// 옵셔널 정수형 변수 `x`를 선언합니다. 이때 변수 `x`는 nil 값을 가질 수 있습니다.
var x : Int?
// 변수 `x`에 정수 10을 할당합니다. 여기서 `x`는 옵셔널이기 때문에 실제로는 `Optional(10)`을 저장하게 됩니다.
x = 10
// `x`가 nil이 아닌지 확인합니다. 즉, `x`에 값이 할당되어 있는지 확인합니다.
if x != nil {
// `x`가 nil이 아닐 경우, `x`의 값을 강제 언래핑하여 출력합니다.
// 강제 언래핑(`!`)은 옵셔널이 값을 가지고 있음을 확신할 때 사용합니다.
// 여기서 `x!`는 옵셔널에서 실제 값을 추출하여 `10`을 출력합니다.
print(x!)
} else {
// `x`가 nil인 경우, 콘솔에 "nil"을 출력합니다.
// 이 코드 블록은 `x`가 nil일 때 실행되지만, 위에서 `x`에 10을 할당했기 때문에 이 블록은 실행되지 않습니다.
print("nil")
}
var x : Int?
x = 10
if let xx = x { // 옵셔널 변수 x가 값을 가지고 있다면, 그 값(10)을 언래핑해서 새로운 상수 xx에 대입하고 if문 내부의 코드를 실행
print(xx) // 옵셔널이 아닌 상태의 x 값, 즉 10을 출력
}
else {
print("nil") // x가 nil이라면 이 블록이 실행됨. 현재 상황에서는 실행되지 않음.
}
?와 ! 사용법 정리
| 선언문에서 | 옵셔널을 선언할 때 사용합니다. 이는 변수가 값을 가지거나 nil을 가질 수 있음을 의미합니다. | 암시적 추출 옵셔널(Implicitly Unwrapped Optionals)을 선언할 때 사용합니다. 이는 프로그램 실행 중 변수가 항상 값을 가질 것이라는 것을 암시하지만, 초기에는 nil을 가질 수 있습니다. |
| 예시 | var x: Int? - x는 Int 타입의 값을 가질 수도 있고, nil을 가질 수도 있습니다. | var y: Int! - y는 프로그램 실행 도중에는 값이 항상 있을 것으로 예상되지만, 초기에는 nil일 수 있습니다. 사용 시 강제 언래핑 없이 직접 사용할 수 있습니다. |
| 실행문에서 | 옵셔널 체이닝(Optional Chaining) 등에서 사용하여 nil을 안전하게 처리할 수 있습니다. 옵셔널 바인딩(if let) 등을 통해 옵셔널 값을 안전하게 추출할 수 있습니다. | 옵셔널 값에 접근하여 그 값을 강제로 언래핑할 때 사용합니다. 이는 옵셔널이 nil이 아니라는 확신이 있을 때만 사용해야 합니다. 강제 언래핑 시, 옵셔널이 nil이면 런타임 에러가 발생합니다. |
| 예시 | if let z = x { print(z) } - x가 nil이 아니면 z에 값을 할당하고 실행합니다. | print(y!) - y가 nil이 아닌 경우, 해당 값을 강제로 언래핑하여 출력합니다. nil일 경우 런타임 에러 발생. |




func multiplyByTen(value: Int?) {
if let num = value {
print(num * 10)
} else {
print("nil임...")
}
}
multiplyByTen(value: 3)
multiplyByTen(value: nil)
ㄴ if let 사용 1
// 옵셔널 인티저 타입의 매개변수를 가지는 함수 multiplyByTen 정의
func multiplyByTen(value: Int?) {
// 옵셔널 바인딩을 사용하여 value가 nil이 아닌지 확인하고, nil이 아닐 경우 number에 할당
if let number = value {
// value가 nil이 아닌 경우, number * 10의 결과를 출력
print(number * 10)
}
else {
// value가 nil인 경우, "Nil입니다."를 출력
print("Nil입니다.")
}
}
// 함수를 테스트하기 위한 호출: value에 5를 전달
multiplyByTen(value: 5) // 출력: 50
// 함수를 테스트하기 위한 호출: value에 nil을 전달
multiplyByTen(value: nil) // 출력: "Nil입니다."
ㄴ if let 사용 2
func multiplyByTen(value: Int?) {
// guard 문을 사용하여 value가 nil이 아닌지 확인합니다.
// value가 nil이라면 guard 문의 else 블록이 실행됩니다.
guard let value else {
print("nil임...")
// nil인 경우 "nil임..."을 출력하고 함수에서 빠져나옵니다.
return
}
// value가 nil이 아니라면, 이 부분이 실행됩니다.
// value는 이 시점에서 이미 옵셔널이 아닌 일반 Int 타입으로 처리됩니다.
print(value * 10)
}
// 함수를 호출하면서 정수 3을 인자로 전달합니다.
// 3은 옵셔널이 아니므로, 함수 내부에서 10을 곱한 30이 출력됩니다.
multiplyByTen(value: 3)
// 함수를 호출하면서 nil을 인자로 전달합니다.
// 이 경우, "nil임..."이 출력됩니다.
multiplyByTen(value: nil)
ㄴ if let을 guard let으로 변경

이렇게 간단하게 표현할 수도 있다.
guard ~ else는 거짓일 때 실행이 되고, break / return / continue / throw와 같은 제어문 전환 키워드가 위치할 수 있는 곳에서 사용할 수 있다. 그리고 else문 이후에 guard에 작성한 변수명으로 옵셔널이 풀린 값을 바로 사용할 수 있다.

guard let은 위와 같은 일반적으로 사용하는 부분에서는 사용할 수 없다. 함수 안에서 옵셔널을 풀 때 주로 사용한다.
그리고 조기 출구 전략을 사용하여 else문에서 제어문을 탈출할 수 있도록하여 이후에 같은 블록 안의 코드를 실행하지 않도록 한다.
// Man 클래스를 정의합니다.
class Man {
// 'age'와 'weight'라는 이름의 두 개의 인스턴스 변수를 선언합니다.
// 'age'는 Int 타입으로, 'weight'는 Double 타입으로 선언됩니다.
var age : Int
var weight : Double
// 'display'라는 함수를 정의합니다. 이 함수는 인스턴스의 'age'와 'weight'를 출력합니다.
func display() {
print("나이=\(age), 몸무게=\(weight)")
}
// 클래스의 초기화 함수(init)를 정의합니다.
// 'age'와 'weight'라는 두 개의 매개변수를 받아, 인스턴스 변수에 할당합니다.
// 이때, 'self' 키워드를 사용하여 인스턴스 변수와 매개변수 이름의 구별을 명확히 합니다.
init(age: Int, weight : Double) {
self.age = age
self.weight = weight
}
}
// 'Man' 클래스의 인스턴스를 생성합니다. 'age'에는 10, 'weight'에는 20.5를 전달합니다.
var kim : Man = Man(age:10, weight:20.5)
// 생성된 인스턴스 'kim'의 'display' 함수를 호출하여, 'age'와 'weight' 정보를 출력합니다.
kim.display()

failable initailizer
https://developer.apple.com/documentation/uikit/uiimage/1624154-init
init(named:in:compatibleWith:) | Apple Developer Documentation
Creates an image object using the named image asset that’s compatible with the specified trait collection.
developer.apple.com

이런식으로 inite다음에 ?가 있으면 failable initializer이다.
문법적으로는 문제가 없지만 논리적으로 원하던 결과로 만들어지지 않는 경우를 방지하기 위해 사용한다.

class Man {
var age : Int
var weight : Double
func display() {
print("나이=\(age), 몸무게=\(weight)")
}
init?(age: Int, weight : Double) {
self.age = age
self.weight = weight
}
}
var kim : Man = Man(age:10, weight:20.5)!
kim.display()
failable initializer를 사용하면 옵셔널로 반환되기 때문에 인스턴스는 옵셔널로 생성된다.
위 처럼 강제 언래핑을 해서 원래의 자료형 형태로 저장할 수 있다.
var kim : Man? = Man(age:10, weight:20.5)
kim!.display()
인스턴스의 내용에 접근하기 위해서는 옵셔널을 풀어야 한다. 위와 같이 메서드를 사용할 때 !로 강제 언래핑해서 사용할 수 있다.
var kim : Man? = Man(age:10, weight:20.5)
if let kim { // 옵셔널 바인딩
kim.display()
}
이런식으로 옵셔널 바인딩을 사용해서 호출할 수도 있다.
if let kim = Man(age:10, weight:20.5) {
kim.display()
}
따로 변수를 선언하지 않고 바로 if문을 이용하여 사용할 수도 있다.

class Man {
var age : Int
var weight : Double
func display() {
print("나이=\(age), 몸무게=\(weight)")
}
// failable initializer
init?(age: Int, weight : Double) {
if age <= 0 || weight <= 0.0 {
return nil
} else {
self.age = age
self.weight = weight
}
}
}
if let kim = Man(age:10, weight:20.5) {
kim.display()
}
if let kim = Man(age:-1, weight:20.5) {
kim.display()
}

원하는 범위가 아닌 경우 nil을 반환하도록 한다.
// Man 클래스 정의
class Man {
// Man 객체의 나이와 몸무게를 저장할 인스턴스 변수 선언
var age : Int
var weight : Double
// 나이와 몸무게를 출력하는 메소드
func display() {
print("나이=\(age), 몸무게=\(weight)")
}
// 실패 가능한 생성자(init?) 정의
// age와 weight가 0 이하일 경우 객체 생성을 실패하도록 하여 nil을 반환
init?(age: Int, weight : Double) {
if age <= 0 || weight <= 0.0 {
return nil
} else {
self.age = age // self를 사용해 인스턴스 변수에 접근
self.weight = weight
}
}
}
// age가 10, weight가 20.5인 Man 객체 생성 시도
// 생성자가 실패 가능한 생성자이므로 결과는 Optional(Man)이 됨
if let kim = Man(age:10, weight:20.5) {
kim.display() // 객체 생성 성공 시 display 메소드 호출
}
// age가 -1(유효하지 않은 값), weight가 20.5인 Man 객체 생성 시도
// 이 경우, 생성자는 nil을 반환할 것임
let kim : Man? = Man(age:-1, weight:20.5)
if let kim {
kim.display() // 이 라인은 실행되지 않음, 생성자에서 nil 반환하기 때문
}
'공부 > Swift' 카테고리의 다른 글
| [iOS][10주차] 박스오피스 앱 만들기 (0) | 2024.05.09 |
|---|---|
| [iOS][8, 9주차] 영화진흥위원회 오픈API 사용하기 (0) | 2024.05.02 |
| [iOS][6주차] TableView & 간단한 앱 만들기 2 / 다운캐스팅, 옵셔널 (0) | 2024.04.11 |
| [iOS][5주차] Swift 문법 복습 / TableView (0) | 2024.04.04 |
| [iOS][3&4주차] 간단한 앱 만들기, 문법 복습 (0) | 2024.03.28 |