5


section / row / cell

image

UITableViewCell

image

직접 디자인 할 셀을 만들었다. (UItableViewCell) identifier를 지정해줘야한다.

Constraints

image

dequeueReusableCell

image

자식으로 바꾸기 위해 as!를 사용해야한다.

image

didSelectRowAt

image

셀을 클릭했을 때 호출되는 메소드이다.

source

import UIKit

// 영화 정보를 저장하는 배열 선언
let image = ["1.png","2.png","3.png","4.png","5.png"] // 영화 포스터 이미지 파일 이름
let name = ["쿵푸팬더4","파묘","남은 인생 10년","댓글부대","오멘: 저주의 시작"] // 영화 제목
let rank = [1,2,3,4,5] // 영화 순위
let open = ["2024-04-10", "2024-02-22", "2023-05-24","2024-03-27", "2024-04-03"] // 영화 개봉일

// UIViewController를 상속받는 ViewController 클래스 선언. UITableViewDelegate와 UITableViewDataSource 프로토콜을 준수하여 테이블 뷰의 기능을 구현합니다.
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    @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
    }
    
    // 각 행에 대한 셀을 구성하는 메소드. 여기서는 MyTableViewCell 클래스를 사용하여 셀을 구성하고, 영화 제목과 개봉일을 셀에 표시합니다.
    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] // 영화 개봉일 설정
        return cell
    }
    
    // 특정 행이 선택되었을 때 호출되는 메소드. 여기서는 선택된 행의 indexPath를 콘솔에 출력합니다.
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        print(indexPath.description)
    }
    
    // 뷰가 로드되었을 때 초기 설정을 수행하는 메소드. 테이블 뷰의 delegate와 dataSource를 self로 설정합니다.
    override func viewDidLoad() {
        super.viewDidLoad()
        table.delegate = self
        table.dataSource = self
    }
}

stack view

image

line, autoshrink

image

line : 줄을 몇개 쓸건지 (0으로 설정하면 여러 줄 사용) autoshrink : 폰트 크기 자동 조절

myLabel, myOpen이 Optional인데 풀지 않는 이유

image

! 옵셔널으로 설정되어있기 때문에 따로 풀지 않아도 알아서 풀린다.

downcasting / upcasting


다운캐스팅(Downcasting)과 업캐스팅(Upcasting)은 객체 지향 프로그래밍에서 사용되는 중요한 개념입니다.

  1. 업캐스팅(Upcasting):
    • 업캐스팅은 하위 클래스의 인스턴스를 상위 클래스의 인스턴스로 캐스팅하는 것을 말합니다.
    • 즉, 하위 클래스의 객체를 상위 클래스의 객체로 변환하는 것을 의미합니다.
    • 업캐스팅은 자동으로 이루어지며, 명시적인 형변환 없이 상위 클래스의 참조 변수에 하위 클래스의 객체를 할당할 수 있습니다.
    • 업캐스팅을 통해 상위 클래스의 메서드와 속성에 접근할 수 있지만, 하위 클래스의 고유한 메서드나 속성에는 접근할 수 없습니다.
  2. 다운캐스팅(Downcasting):
    • 다운캐스팅은 상위 클래스의 인스턴스를 하위 클래스의 인스턴스로 캐스팅하는 것을 말합니다.
    • 즉, 상위 클래스의 객체를 하위 클래스의 객체로 변환하는 것을 의미합니다.
    • 다운캐스팅은 명시적으로 형변환을 해주어야 하며, 이때 캐스팅이 유효한지를 확인해야 합니다. (예: as? 또는 as! 연산자를 사용하여 캐스팅)
    • 다운캐스팅을 통해 하위 클래스의 고유한 메서드나 속성에 접근할 수 있습니다.

간단히 말하면, 업캐스팅은 하위 클래스를 상위 클래스로 변환하는 것이며, 다운캐스팅은 상위 클래스를 하위 클래스로 변환하는 것입니다. 업캐스팅은 자동으로 이루어지지만, 다운캐스팅은 명시적으로 형변환을 해주어야 하며, 유효성을 확인해야 합니다.

image

image

예제

class Animal {}
class Dog : Animal {}
let myDog : Dog = Dog()
let myAnimal : Animal = myDog
//모든 강아지는 동물이다
// 안전한 Downcasting
let someAnimal: Animal = Dog()
print(type(of:someAnimal)) //Dog
let x = someAnimal as? Dog
//as?는 안전(옵셔널로 반환, 실패하면 nil반환)
print(type(of:x)) //Optional<Dog>
if let someDog = someAnimal as? Dog {
    print(type(of:someDog)) //Dog
} else {
    print("Downcasting 실패.")
}
// 강제적인 Downcasting
let anotherDog = someAnimal as! Dog //강제적인 방법(실패 시 런타임 오류 발생)
//someAnimal이 Dog의 인스턴스가 아니면 런타임 오류 발생
print(type(of:anotherDog)) //Dog

위의 Swift 코드는 클래스 상속과 타입 캐스팅(업캐스팅과 다운캐스팅)에 대한 예제입니다. 각 부분에 대한 자세한 설명은 다음과 같습니다:

  1. 클래스 정의:
    • Animal이라는 기본 클래스를 정의합니다.
    • Dog 클래스는 Animal 클래스를 상속받습니다. 즉, DogAnimal의 하위 클래스입니다.
  2. 업캐스팅:
    • let myDog : Dog = Dog()Dog 타입의 인스턴스를 생성하고 myDog 변수에 할당합니다.
    • let myAnimal : Animal = myDog에서 myDog 인스턴스(하위 클래스 타입)를 myAnimal 변수(상위 클래스 타입)에 할당합니다. 이 과정에서 업캐스팅이 자동으로 발생합니다. 모든 DogAnimal이기 때문에 이러한 할당은 안전합니다.
  3. 다운캐스팅 시도:
    • let someAnimal: Animal = Dog()Dog 인스턴스를 생성하고 이를 Animal 타입의 변수 someAnimal에 할당합니다. 이는 업캐스팅의 예입니다.
    • print(type(of:someAnimal))someAnimal의 타입을 출력합니다. 결과는 Dog입니다. 이는 someAnimal이 실제로 Dog 인스턴스를 가리키고 있음을 나타냅니다.
    • let x = someAnimal as? Dog는 안전한 다운캐스팅을 시도합니다. as? 연산자는 실패할 경우 nil을 반환합니다. 여기서는 someAnimal이 실제로 Dog 타입이므로 다운캐스팅이 성공하고 xOptional<Dog> 타입이 됩니다.
    • if let someDog = someAnimal as? Dog는 옵셔널 바인딩을 사용하여 someAnimalDog 타입으로 안전하게 다운캐스팅합니다. 다운캐스팅이 성공하면 someDog 변수에 할당되고, 실패하면 else 블록이 실행됩니다.
  4. 강제 다운캐스팅:
    • let anotherDog = someAnimal as! Dog는 강제 다운캐스팅을 시도합니다. as! 연산자는 다운캐스팅이 실패할 경우 런타임 오류를 발생시킵니다. 여기서는 someAnimal이 실제로 Dog 인스턴스이므로 다운캐스팅이 성공하고 오류가 발생하지 않습니다.

이 예제는 업캐스팅이 자동으로 이루어지며 안전하다는 것과, 다운캐스팅을 할 때는 as?를 사용하여 안전하게 시도하거나, 확신이 있을 때만 as!를 사용하여 강제로 시도해야 한다는 것을 보여줍니다.

Optional Chaining

예제

// Person 클래스 정의
class Person {
    var name: String // 이름을 저장하는 변수
    var age: Int // 나이를 저장하는 변수
    
    // 초기화 메소드. 인스턴스 생성 시 이름과 나이를 설정할 수 있습니다.
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

// Person 인스턴스 생성 및 사용
let kim: Person = Person(name: "Kim", age: 20) // 'Kim'이라는 이름과 20이라는 나이로 Person 인스턴스 생성
print(kim.age) // 20 출력

// 옵셔널 Person 인스턴스 생성 및 사용
let han: Person? = Person(name: "Han", age: 25) // 'Han'이라는 이름과 25라는 나이로 옵셔널 Person 인스턴스 생성
// print(han?.age) //error - 이 줄은 실제로는 에러를 발생시키지 않으며, 옵셔널 체이닝을 사용하여 옵셔널 값을 안전하게 접근합니다.
print(han!.age) // 강제 언래핑을 사용하여 옵셔널 값을 접근. 주의: 옵셔널 값이 nil일 경우 런타임 에러 발생
print(han?.age) // 옵셔널 체이닝을 사용하여 옵셔널 값을 안전하게 접근. 결과는 Optional(25)로 출력됩니다.
print((han?.age)!) // 옵셔널 체이닝 후 강제 언래핑을 사용하여 값을 접근. 25 출력

// 옵셔널 바인딩을 사용하여 옵셔널 값을 안전하게 언래핑
if let hanAge = han?.age {
    print(hanAge) // 옵셔널 값이 nil이 아닐 경우, hanAge 변수에 값을 할당하고 출력
} else {
    print("nil") // 옵셔널 값이 nil일 경우 "nil" 출력
}

옵셔널을 언래핑하는 여러가지 방법

// 옵셔널 변수 x 선언 및 초기화
var x: String? = "Hi" // x는 옵셔널 String 타입. 초기값으로 "Hi"를 가짐. "Hi"를 지우면 x는 nil 값을 가짐.

// 옵셔널 변수 x의 값과 강제 언래핑된 값을 출력
print(x, x!) // 첫 번째 x는 옵셔널 값을 그대로 출력. 두 번째 x!는 강제 언래핑을 통해 옵셔널을 벗겨내고 값을 출력.

// 옵셔널 바인딩을 사용하여 x의 값을 안전하게 언래핑
if let a = x {
    print(a) // x가 nil이 아니면 a에 x의 값을 할당하고 출력. x가 nil이면 이 블록은 실행되지 않음.
}

// 강제 언래핑을 사용하여 x의 문자열 길이를 구함
let b = x!.count // x!를 통해 강제 언래핑. x가 nil일 경우 런타임 에러 발생.
print(type(of:b), b) // b의 타입(Int)과 값을 출력.

// 옵셔널 체이닝을 사용하여 x의 문자열 길이를 안전하게 구함
let b1 = x?.count // x?를 통해 옵셔널 체이닝. x가 nil이면 b1도 nil.
print(type(of:b1), b1, b1!) // b1의 타입(Optional<Int>), 옵셔널 값, 강제 언래핑된 값을 출력.

// nil 병합 연산자를 사용하여 x의 값을 안전하게 언래핑하거나 기본값 제공
let c = x ?? "" // x가 nil이 아니면 x의 값을 사용, nil이면 빈 문자열("")을 사용.
print(c) // c의 값을 출력.








출처


  • Smile Han의 iOS 프로그래밍 실무, 한성현(출판 예정), PPT로 제공
  • Do it! 스위프트로 아이폰 앱 만들기 입문(개정 7판)(이지스퍼블리싱,송호정, 이범근, 2023.1)
  • 핵심만 골라 배우는 SwiftUI 기반의 iOS 프로그래밍(제이펍, 닐 스미스, 2023.12)
    • https://www.techotopia.com/index.php/IOS_iPhone_iPad_eBooks
  • 스위프트 프로그래밍(Swift 5) 3판(한빛미디어, 야곰, 2019.10)
  • 꼼꼼한 재은 씨의 스위프트 기본편 (루비페이퍼, 이재은, 2018.05)
  • 꼼꼼한 재은 씨의 스위프트 실전편 (Swift) (루비페이퍼, 이재은, 2018.08)
  • 꼼꼼한 재은 씨의 Swift 문법편 (루비페이퍼, 이재은, 2017.12)