본문 바로가기

카테고리 없음

iOS 프로그래밍 실무 6주차

 

중요시험* didSelectRowAt: 보이는 셀을 리턴 *

//

//  ViewController.swift

//  tableA

//

//  Created by 컴소뉴맥 on 2026/04/13.

//

 

import UIKit

 

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

  //부모:자식, 친구(알바생,프로토콜),친구(알바생,프로토콜)

 

    @IBOutlet weak var table: UITableView!

    

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

        return 5

    }

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

        print(indexPath.description) //didSelectRowAt: 보이는 셀을 리턴

    }

    

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

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

        cell.myLabel.text = name[indexPath.row]

        print(indexPath.row)

        return cell

    }

    func numberOfSections(in tableView: UITableView) -> Int {

        return 7

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()

        table.delegate = self

        table.dataSource = self

    }

 

}

import UIKit
 

👉 iOS에서 UI를 만들 때 사용하는 기본 프레임워크
(버튼, 테이블, 화면 등 전부 포함)


 
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
 

👉 클래스 선언

  • UIViewController 👉 화면 하나를 관리하는 부모 클래스
  • UITableViewDelegate 👉 사용자 동작 처리 (클릭 등)
  • UITableViewDataSource 👉 테이블에 데이터 공급

💡 즉,
👉 “이 클래스가 테이블의 데이터 + 이벤트를 다 담당한다”는 의미


 
@IBOutlet weak var table: UITableView!
 

👉 스토리보드에 있는 테이블뷰와 연결된 변수

  • @IBOutlet 👉 UI 연결용 키워드
  • weak 👉 메모리 순환 참조 방지
  • ! 👉 nil이 아님을 가정 (강제 옵셔널)

 
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
 

👉 한 섹션에 들어갈 행(row) 개수

  • section 👉 현재 섹션 번호
  • 항상 5를 반환 → 각 섹션마다 5개 셀 생성

 
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath.description)
}
 

👉 셀을 클릭했을 때 실행되는 함수 (Delegate)

  • indexPath 👉 클릭된 위치 정보
    • section
    • row
 
print(indexPath.description)
 

👉 클릭한 위치를 콘솔에 출력
예: [0, 2] → 0번 섹션, 2번 셀

💡 주의
👉 “셀을 리턴하는 함수”가 아니라
👉 “클릭 이벤트를 처리하는 함수”


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

👉 테이블의 각 셀을 만드는 핵심 함수

  • 테이블이 셀 하나 필요할 때마다 호출됨

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

👉 셀 재사용 (매우 중요 ⭐)

  • dequeueReusableCell 👉 재사용 가능한 셀 가져오기
  • "myCell" 👉 스토리보드에서 설정한 Identifier
  • as! MyTableViewCell 👉 커스텀 셀로 강제 형변환

💡 이유
👉 셀을 계속 새로 만들면 메모리 낭비 → 재사용


 
cell.myLabel.text = name[indexPath.row]
 

👉 셀에 데이터 넣기

  • indexPath.row 👉 몇 번째 줄인지
  • name 배열에서 해당 값 가져옴

❗ 주의
👉 name 배열이 반드시 선언되어 있어야 함


 
print(indexPath.row)
 

👉 현재 생성 중인 셀의 row 번호 출력
(디버깅용)


 
return cell
 

👉 완성된 셀을 테이블에 전달


 
func numberOfSections(in tableView: UITableView) -> Int {
return 7
}
 

👉 테이블의 섹션 개수

  • 7개의 섹션 생성

 
override func viewDidLoad() {
super.viewDidLoad()
 

👉 화면이 처음 로드될 때 실행되는 함수


 
table.delegate = self
table.dataSource = self
 

👉 테이블에게 역할 지정

  • delegate 👉 클릭, 스크롤 같은 이벤트 처리
  • dataSource 👉 데이터 공급

💡 이거 안 하면 테이블 안 나옴 (중요 ⭐)


📊 전체 동작 흐름

1️⃣ 앱 실행 → viewDidLoad 호출
2️⃣ 테이블이 데이터 요청
3️⃣ 섹션 개수 요청 → 7
4️⃣ 각 섹션마다 행 개수 요청 → 5
5️⃣ 셀을 하나씩 생성 (cellForRowAt)
6️⃣ 사용자 클릭 → didSelectRowAt 실행


❗ 코드에서 꼭 짚고 넘어갈 부분

1️⃣ 총 셀 개수

👉 7 섹션 × 5 행 = 35개 셀


2️⃣ 데이터 문제 가능성

 
name[indexPath.row]
 

👉 모든 섹션이 같은 데이터 사용

→ 보통은 이렇게 안 하고
👉 section까지 포함해서 데이터 구조 만듦


💡 핵심 요약

👉 DataSource

  • 몇 개 만들지
  • 셀 내용 무엇인지

👉 Delegate

  • 클릭했을 때 뭐 할지

 

import UIKit // iOS UI를 만들기 위한 기본 프레임워크

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    // UIViewController를 상속받고,
    // UITableView의 이벤트 처리(Delegate)와 데이터 제공(DataSource)을 담당하는 클래스

    @IBOutlet weak var table: UITableView!
    // 스토리보드에 있는 UITableView와 연결된 변수

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // 각 섹션(section)마다 몇 개의 행(row)을 만들지 결정하는 함수
        return 5 // 모든 섹션에 5개의 셀 생성
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        // 사용자가 셀을 클릭했을 때 호출되는 함수 (Delegate 역할)

        print(indexPath.description)
        // 클릭한 셀의 위치 출력 (예: [section, row])

        // ❗ 주의: 셀을 "리턴"하는 함수가 아니라
        // 클릭 이벤트를 처리하는 함수임
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // 각 셀을 생성하고 내용을 설정하는 가장 중요한 함수

        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! MyTableViewCell
        // 재사용 가능한 셀을 가져옴 (메모리 효율)
        // "myCell"은 스토리보드에서 설정한 Identifier
        // MyTableViewCell 타입으로 강제 형변환

        cell.myLabel.text = name[indexPath.row]
        // 셀의 라벨에 데이터 넣기
        // indexPath.row는 현재 행 번호
        // ❗ name 배열이 미리 정의되어 있어야 함

        print(indexPath.row)
        // 현재 생성 중인 셀의 row 번호 출력 (디버깅용)

        return cell
        // 완성된 셀을 테이블뷰에 반환
    }

    func numberOfSections(in tableView: UITableView) -> Int {
        // 테이블뷰의 섹션 개수를 설정하는 함수
        return 7 // 총 7개의 섹션 생성
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // 뷰가 처음 로드될 때 실행되는 함수

        table.delegate = self
        // 테이블의 이벤트(클릭, 스크롤 등)를 이 클래스에서 처리

        table.dataSource = self
        // 테이블에 표시할 데이터도 이 클래스에서 제공
    }
}

💡 핵심 요약 (짧게 정리)

  • DataSource → 셀 개수 + 내용 설정
  • Delegate → 클릭 같은 사용자 이벤트 처리
  • indexPath → (섹션, 행) 위치 정보
  • dequeueReusableCell → 셀 재사용 (성능 핵심)

------------------------------------------------------------------------------------------------------------

 

<Optional Chaining>

var x : Int? => nil

x = 10

 

🍬 옵셔널 체이닝 한 줄 정의

👉 값이 있으면 계속 진행하고, 없으면 그냥 nil 반환하는 것


🧱 왜 필요할까?

Swift에서는 값이 **없을 수도 있는 변수(옵셔널)**가 있어요.

예:

 
var name: String? // 값이 있을 수도, 없을 수도 있음
 

❌ 문제 상황

 
print(name.count)
 

👉 name이 nil이면?
💥 앱 크래시 (에러 발생)


✅ 옵셔널 체이닝 사용

 
print(name?.count)
 

👉 의미:

  • name이 있으면 → count 실행
  • 없으면 → 그냥 nil

👉 절대 안 터짐 👍


🧠 핵심 개념

 
?.
 

👉 뜻:
"이거 있으면 다음 실행해"


🔗 연결되는 구조 (체이닝)

 
person?.home?.address?.city
 

👉 해석:

  1. person 있으면
  2. home 있으면
  3. address 있으면
  4. city 가져오기

👉 중간에 하나라도 없으면 → 바로 nil


🍕 쉬운 비유

👉 자동문 🚪

  • 사람이 있으면 → 문 열림
  • 사람이 없으면 → 아무 일도 안 일어남

👉 ? = 자동문


❗ 결과 특징

 
let length = name?.count
 

👉 결과 타입:

 
Int?
 

👉 왜?
→ 중간에 nil 될 수 있으니까


🎯 핵심 요약

  • ? = 안전하게 접근
  • 값 있으면 실행
  • 없으면 nil 반환
  • 절대 크래시 안 남

 

 

**

if let a = x {

    print(a)

} //옵셔널 바인딩

 

var x : String? //= "Hi"//Hi지우고도 실습

 

//print(x, x!)

 

if let a = x {

    print(a)

} //옵셔널 바인딩

 

let b = x!.count -> x의 값은 nil 풀면 x

print(type(of:b),b)

 

let b1 = x?.count //조심스럽게 풀음

print(type(of:b1),b1, b1!)

 

let c = x ?? ""

print(c)

중요 예시(이것만 기억)

 

 

 

class Person {

    var name: String

    var age: Int

    init(name: String, age: Int) {

        self.name = name

        self.age = age

    }

}

let kim: Person = Person(name: "Kim", age: 20)

print(kim.age)

let han: Person? = Person(name: "Han", age: 25) //옵셔널 -> 값이 없을 수도 있음

//print(han.age) //에러 ->풀어서 접근

print(han!.age)

print(han?.age) // ?조심스럽게 접근->크래시 방지 //Optional(25), 옵셔널 체이닝

print((han?.age)!)

 

 if let hanAge = han?.age {

 print(hanAge)

} else {

 print("nil")

 }

 

🍬 예제 1: 가장 기본

 
var name: String? = "Tom"

print(name?.count)
 

👉 설명

  • name이 있으면 → 글자 수 출력
  • 없으면 → nil

👉 결과:

Optional(3)
 

 
name = nil
print(name?.count)
 

👉 결과:

nil
 

👉 핵심

  • 값 없으면 그냥 nil
  • 절대 에러 안 남 👍

🍬 예제 2: 객체 안의 값 접근

 
class Dog {
var name: String = "Coco"
}

var dog: Dog? = Dog()

print(dog?.name)
 

👉 설명

  • dog가 있으면 → name 가져오기
  • 없으면 → nil

👉 결과:

Optional("Coco")
 

 
dog = nil
print(dog?.name)
 

👉 결과:

nil
 

🍬 예제 3: 여러 단계 체이닝 (중요 ⭐)

 
class Address {
var city: String = "Seoul"
}

class Person {
var address: Address? = Address()
}

var person: Person? = Person()

print(person?.address?.city)
 

👉 설명 (흐름)

  1. person 있나?
  2. address 있나?
  3. city 가져오기

👉 결과:

Optional("Seoul")
 

 
person?.address = nil
print(person?.address?.city)
 

👉 결과:

nil
 

👉 중간에 하나라도 nil이면 전체가 nil


🍬 예제 4: 함수 호출

 
class Cat {
func sound() {
print("야옹")
}
}

var cat: Cat? = Cat()

cat?.sound()
 

👉 설명

  • cat이 있으면 → sound 실행
  • 없으면 → 아무 일도 안 일어남

👉 결과:

야옹
 

 
cat = nil
cat?.sound()
 

👉 결과:
👉 아무 출력 없음 (조용함)


🧠 핵심 정리

👉 ?. 의미
"있으면 실행, 없으면 멈춤"


🎯 진짜 중요한 포인트

  • 중간에 하나라도 nil → 전체 결과 nil
  • 앱이 절대 크래시 안 남
  • 결과는 항상 옵셔널 타입

💡 한 줄 요약

👉 옵셔널 체이닝 = 안전하게 연결해서 값 꺼내는 방법

 

 

-------------------------------------------------------------------------------------------------------------------

오류 처리 <Error Handling>

📊 Error Handling 방법 비교표

방법설명대표 문법특징사용 언어 예시
try-catch 에러가 발생할 수 있는 코드를 감싸고, 에러를 잡아서 처리 try { } catch { } 가장 일반적이고 강력 Swift, Java, Python
throws (던지기) 함수에서 에러를 직접 처리하지 않고 호출한 쪽으로 넘김 throws 책임을 위로 전달 Swift, Java
Optional (nil 처리) 값이 없을 수 있음을 nil로 표현 ? 간단하지만 상세한 에러 정보 없음 Swift
Result 타입 성공/실패를 하나의 값으로 반환 Result<T, Error> 함수형 스타일 Swift, Rust
if/else 체크 조건문으로 직접 에러 상황 처리 if (x == nil) 가장 단순하지만 반복 많음 모든 언어
assert 특정 조건이 맞지 않으면 프로그램 중단 assert() 디버깅용 Swift, Python
panic / fatalError 치명적 에러 발생 시 즉시 종료 fatalError() 복구 불가능 상황 Swift, Rust
error code 반환 숫자/코드로 에러 상태 전달 return -1 C 스타일 C, C++
logging 에러를 기록만 하고 계속 실행 print/log 디버깅 및 추적용 모든 언어

📌 Swift 기준으로 핵심 4가지

Swift에서는 특히 이 4개가 중요합니다 👇

1️⃣ try-catch

 
do {
try someFunction()
} catch {
print("에러 발생")
}
 

2️⃣ throws

 
func someFunction() throws {
// 에러 발생 가능
}
 

3️⃣ Optional

 
let value: Int? = nil
 

👉 값 없으면 nil로 처리


4️⃣ Result 타입

 
let result: Result<Int, Error>
 

👉 성공 vs 실패를 명확히 구분

swift 오류 제어

throwing function(시험*)

AVAudioPlayer 

throws 매소드 메게변수 ()다음에 화살표(->)앞에 사용

예외 처리를 할때 리턴값이 있을 경우 리턴값을 작성한다 

(throws매소드는 반드시 예외처리를 해야한다)

 

do~catch 예제

🍬 예제: 숫자 나눗셈 (0으로 나누기 에러)

1️⃣ 에러 타입 만들기

 
enum MathError: Error {
case divideByZero
}
 

👉 의미

  • Error 프로토콜을 따르는 에러 종류 정의
  • 여기서는 “0으로 나누기” 에러만 있음

2️⃣ 에러를 던지는 함수

 
func divide(_ a: Int, _ b: Int) throws -> Int {
if b == 0 {
throw MathError.divideByZero
}
return a / b
}
 

👉 설명

  • throws 👉 이 함수는 에러 발생 가능
  • throw 👉 실제로 에러 발생시키기

3️⃣ do-catch로 처리

 
do {
let result = try divide(10, 0)
print(result)
} catch {
print("에러 발생!")
}
 

👉 결과

에러 발생!
 

🎯 흐름 정리

  1. try divide(10, 0) 실행
  2. b == 0 → 에러 발생 (throw)
  3. catch로 이동
  4. 에러 메시지 출력

🍬 에러 종류별로 처리 (조금 더 발전)

 
do {
let result = try divide(10, 0)
print(result)
} catch MathError.divideByZero {
print("0으로 나눌 수 없습니다!")
} catch {
print("알 수 없는 에러")
}
 

👉 결과

0으로 나눌 수 없습니다!
 

🧠 핵심 개념

  • throws 👉 에러 던질 수 있음
  • throw 👉 에러 발생
  • try 👉 에러 날 수 있는 코드 실행
  • do-catch 👉 에러 잡기

💡 한 줄 요약

👉 do-catch는 “에러가 나면 여기서 잡아서 처리하겠다”는 구조

🚨 에러 메시지 해석

Call can throw, but it is not marked with 'try' and the error is not handled

👉 쉽게 번역하면:

👉 “이 함수는 에러(throw)를 발생시킬 수 있는데,
너는 try도 안 썼고 do-catch로도 처리 안 했어!”


📌 왜 이런 에러가 생기냐?

Swift에서는 에러 가능한 함수에 반드시 표시가 있어요:

 
func divide(_ a: Int, _ b: Int) throws -> Int
 

👉 throws = “이 함수 에러 날 수 있음”


❌ 잘못된 사용

 
let result = divide(10, 0)
 

👉 문제:

  • 에러 날 수 있는 함수인데
  • try도 없음
  • do-catch도 없음

💥 그래서 컴파일 에러 발생


✅ 해결 방법 3가지


1️⃣ try + do-catch (정석 👍)

 
do {
let result = try divide(10, 0)
print(result)
} catch {
print("에러 발생")
}
 

👉 가장 안전한 방법


2️⃣ try? (간단 처리)

 
let result = try? divide(10, 0)
 

👉 에러 나면 nil


3️⃣ try! (위험하지만 간단)

 
let result = try! divide(10, 0)
 

👉 에러 나면 💥 앱 크래시


🧠 핵심 원리

Swift는 일부러 이렇게 강하게 체크함:

👉 “에러 날 가능성 있는데 무시하면 위험하니까 꼭 처리해!”


🎯 한 줄 정리

👉 이 에러는
“throw 가능한 함수인데 try 또는 에러 처리를 안 해서 생긴 컴파일 에러”

 

 

-------------------------------------------------------------------------------------------------------------------

Generic <>

📌 1️⃣ 가장 중요한 역할: 제네릭(Generic)

👉 “어떤 타입이든 받을 수 있게 만드는 기능”

Swift 예시:

 
func printValue<T>(value: T) {
print(value)
}
 

🔍 설명

  • T = 아직 정해지지 않은 타입
  • <> 안에 타입을 넣을 수 있는 “틀”

프로그래밍언어에서 [],{},(),<>

📌 프로그래밍 기호 기본 의미

기호이름역할쉬운 설명
() 괄호 (parentheses) 함수 호출 / 계산 우선순위 “이거 먼저 해!”
[] 대괄호 (square brackets) 배열 / 리스트 / 인덱스 “여러 개 모아놓기”
{} 중괄호 (curly braces) 코드 블록 “여기부터 여기까지 한 덩어리”
<> 꺾쇠 괄호 (angle brackets) 제네릭 / 타입 지정 “타입을 나중에 정함”

🍬 1️⃣ ()

👉 괄호 = “실행 / 묶기”

예제

 
print(1 + 2)
 

👉 먼저 계산하고 실행


함수 호출

 
sayHello()
 

👉 “이 함수 실행해!”


🍬 2️⃣ []

👉 대괄호 = “리스트 / 배열 / 위치”

배열

 
let arr = ["A", "B", "C"]
 

특정 값 꺼내기

 
print(arr[0])
 

👉 A 출력 (0번째)


💡 느낌
👉 “여러 개 담는 상자”


🍬 3️⃣ {}

👉 중괄호 = “코드 묶음”

함수

 
func hello() {
print("Hi")
}
 

if문

 
if true {
print("ok")
}
 

💡 느낌
👉 “여기부터 여기까지 하나의 블록”


🍬 4️⃣ <>

👉 꺾쇠 = “타입을 나중에 넣는 틀”

Swift 제네릭

 
func printValue<T>(value: T) {
print(value)
}
 

👉 T = 어떤 타입이든 가능


배열 타입

 
let arr: Array<Int> = [1, 2, 3]
 

💡 느낌
👉 “비어있는 상자 (나중에 타입 결정)”


🎮 한눈에 비유

기호비유
() 버튼 누르기
[] 상자 / 리스트
{} 방 / 구역
<> 템플릿 / 틀

🎯 핵심 정리

  • () → 실행 / 함수
  • [] → 여러 개 / 인덱스
  • {} → 코드 영역
  • <> → 타입 틀 (제네릭)

제네릭 지원하는 대표 프로그래밍 언어들

🟦 1️⃣ 모바일 / 앱 개발

  • Swift (iOS)
  • Kotlin (Android)
  • Java (Android/Backend)

👉 거의 모든 모바일 메인 언어는 제네릭 지원


🟨 2️⃣ 웹 개발

  • TypeScript (JavaScript 상위)
  • JavaScript (제네릭은 TS에서 주로 사용)
  • Dart (Flutter)

🟥 3️⃣ 시스템 / 고성능

  • C++
  • Rust
  • Go (제네릭은 Go 1.18+ 이후 지원)

🟩 4️⃣ 백엔드 / 서버

  • Java
  • Kotlin
  • C#
  • Scala
  • Python (런타임 제네릭은 약하지만 typing에서 지원)

🟪 5️⃣ 기타 언어

  • Haskell
  • Swift (이미 포함)
  • Objective-C (제한적)
  • F#
  • OCaml

📊 한눈에 핵심 정리

분야언어
모바일 Swift, Kotlin, Java
TypeScript, JavaScript(부분), Dart
시스템 C++, Rust, Go
서버 Java, Kotlin, C#, Scala
함수형 Haskell, F#, OCaml

🧠 중요한 포인트

👉 요즘 “현대 언어 = 거의 다 제네릭 지원”

왜냐하면:

  • 코드 재사용 ↑
  • 타입 안정성 ↑
  • 버그 감소 ↑

🍬 아주 쉽게 이해

제네릭 없는 코드:

 
Int용 함수
String용 함수
Double용 함수
→ 다 따로 만들어야 함
 

제네릭 있는 코드:

 
하나의 함수로 모든 타입 처리
 

🎯 핵심 한 줄

👉 제네릭은 거의 모든 현대 프로그래밍 언어에 있는 “기본 기능”이다

 

Swift Generic

-> 자료형이 실행할때 결정되는 방식

 

func myPrint<T> (a: T, b: T) {

    //myPrint는 결정되지 않은 자료형이 있다-> T

    print(b,a)

}

myPrint(a:1,b:2)

myPrint(a:Int(2.5),b:Int(3.5))//double형

func myPrint<T> (a: T, b: T) {

    //myPrint는 결정되지 않은 자료형이 있다-> T

    print(b,a)

}

myPrint(a:1,b:2)

myPrint(a:2.5,b:3.5)//double형

myPrint(a: "aaa", b: "bbb")

 

->출력값

2 1

3.5 2.5

bbb aaa

 

class Box<T> { //클래스 이름 뒤 <>를 사용(제너릭 클래스)

    var item: T

    init(item: T) {

        self.item = item

    }//이니셜 라이저

    func getItem() -> T {

        return item

    }

} //일반 클래스

let intBox = Box<Int>(item: 12)

// Box<Int>(item: 123), generic class는 이렇게 쓰지만 타입 추론으로 <Int> 생략 가능

print(intBox.getItem()) // 12

let stringBox = Box(item: "Hello") //Box<String>(item: "Hello")

print(stringBox.getItem()) // Hello

📦 1️⃣ 제네릭 클래스 선언

 
class Box<T> {
 

👉 의미:

  • Box라는 “상자 클래스” 만들기
  • <T> = 아직 타입이 정해지지 않은 자리

💡 쉽게 말하면:

“이 상자에는 어떤 타입이든 들어갈 수 있어”

예:

  • Int 넣을 수도 있고
  • String 넣을 수도 있음

📦 2️⃣ 변수 선언

 
var item: T
 

👉 의미:

  • item은 상자 안의 내용물
  • 타입은 T (나중에 결정됨)

💡 즉:

“아직 모르지만 어떤 타입이든 하나 들어올 거야”


📦 3️⃣ 초기화 (init)

 
init(item: T) {
self.item = item
}
 

👉 의미:

  • Box를 만들 때 값을 넣어줘야 함
  • 넣은 값을 item에 저장

💡 예:

 
Box(item: 10)
 

👉 10이 item에 들어감


📦 4️⃣ 값 꺼내기 함수

 
func getItem() -> T {
return item
}
 

👉 의미:

  • 상자 안에 있는 값을 꺼내는 함수
  • 반환 타입도 T (같은 타입 유지)

💡 즉:

“넣은 타입 그대로 꺼내준다”


🧪 5️⃣ Int 타입으로 사용

 
let intBox = Box<Int>(item: 12)
 

👉 의미:

  • T = Int로 결정됨
  • 이제 Box는 “Int 전용 상자”

💡 내부적으로:

 
var item: Int
 

 
print(intBox.getItem())
 

👉 결과:

12
 

🧪 6️⃣ String 타입으로 사용

 
let stringBox = Box(item: "Hello")
 

👉 여기 중요한 포인트 ⭐

Swift는 타입을 자동으로 추론함

👉 컴파일러가 이렇게 이해:

 
Box<String>(item: "Hello")
 

 
print(stringBox.getItem())
 

👉 결과:

Hello
 

🧠 핵심 개념 정리

📌 1. T의 의미

👉 “아직 모르는 타입 자리”


📌 2. 한 번 정해지면 고정

 
Box<Int>
 

👉 이 Box는 절대 String 못 넣음


📌 3. 타입 안전성

👉 잘못 쓰면 에러

 
// Box<Int>에 String 넣기 ❌
 

🍬 쉬운 비유

👉 Box<T> = “종이 상자”

  • 만들 때 라벨 붙임
    • Int 상자 📦
    • String 상자 📦

👉 한번 정하면 바꿀 수 없음


🎯 핵심 요약

  • <T> = 타입 자리 예약
  • Box<T> = 어떤 타입이든 담을 수 있는 상자
  • 생성할 때 타입 결정됨
  • 이후에는 그 타입만 사용 가능

💡 한 줄 정리

👉 제네릭은 “하나의 코드로 여러 타입을 처리하는 기술”

 

 

class Box<T> { 
    // 제네릭 클래스 선언
    // <T>는 "아직 정해지지 않은 타입 자리"
    // Int, String, Double 등 어떤 타입이든 들어올 수 있음

    var item: T
    // item 변수의 타입은 T
    // 즉, Box를 만들 때 T가 결정되면 item 타입도 같이 결정됨

    init(item: T) {
        // 생성자 (init)
        // Box를 만들 때 item 값을 반드시 넣어줘야 함

        self.item = item
        // 전달받은 item 값을 클래스의 item에 저장
    }

    func getItem() -> T {
        // item 값을 꺼내는 함수
        // 반환 타입도 T (입력 타입과 동일하게 유지됨)

        return item
        // 저장된 item 값을 그대로 반환
    }

// 👉 이 클래스는 "어떤 타입이든 담을 수 있는 상자(Box)" 역할


// ==========================
// 1️⃣ Int 타입으로 Box 사용
// ==========================

let intBox = Box<Int>(item: 12)
// Box<Int> → T가 Int로 결정됨
// 즉, item의 타입은 Int가 됨
// item에 12를 넣어서 intBox 생성

// 참고:
// Box<Int>(item: 12) 이렇게 명시적으로 써도 되고
// Swift가 타입을 추론해서 Box(item: 12)로도 가능

print(intBox.getItem())
// getItem() 호출 → item 반환
// 결과: 12


// ==========================
// 2️⃣ String 타입으로 Box 사용
// ==========================

let stringBox = Box(item: "Hello")
// <String> 생략됨 (타입 추론)
// Swift가 자동으로 Box<String>으로 판단

// 내부적으로는 이렇게 해석됨:
// let stringBox = Box<String>(item: "Hello")

print(stringBox.getItem())
// getItem() 호출 → item 반환
// 결과: "Hello"

🧠 핵심 정리 (진짜 중요)

📌 1. <T> 의미

👉 “타입을 나중에 결정하겠다”


📌 2. Box<Int>

👉 T = Int로 고정됨
👉 이제 이 Box는 Int 전용


📌 3. Box<String>

👉 T = String으로 고정됨
👉 문자열 전용 Box


📌 4. 타입 추론

 
Box(item: "Hello")
 

👉 Swift가 자동으로:

 
Box<String>
 

🎮 쉬운 비유

👉 Box<T> = “택배 상자”

  • 만들 때 라벨 붙임
    • 📦 Int 상자
    • 📦 String 상자

👉 한 번 정하면 내용물 종류 고정


💡 한 줄 요약

👉 제네릭 클래스는 “하나의 코드로 여러 타입을 담는 상자”

 

--------------------------------------------------------------------------------------------------------------

Collection Type

3가지

📦 1️⃣ Array (배열)

👉 순서가 있는 값들의 모음

 
let numbers = [1, 2, 3, 4]
 

📌 특징

  • 순서 있음 (index 존재)
  • 중복 허용
  • numbers[0]처럼 접근

📌 예시

 
print(numbers[0]) // 1
 

💡 비유:
👉 “줄 서 있는 사람들”


📦 2️⃣ Dictionary (딕셔너리)

👉 키(Key) - 값(Value) 구조

 
let user = [
"name": "Tom",
"age": 20
]
 

📌 특징

  • 순서 없음
  • key로 값 찾음
  • key는 유일해야 함

📌 예시

 
print(user["name"]) // Optional("Tom")
 

💡 비유:
👉 “사전 (단어 → 뜻)”


📦 3️⃣ Set (집합)

👉 중복 없는 값들의 모음

 
let set: Set<Int> = [1, 2, 3, 3, 2]
print(set) // [1, 2, 3]
 

📌 특징

  • 중복 제거됨
  • 순서 없음
  • 빠른 검색

💡 비유:
👉 “중복 없는 명단”


📊 한눈에 비교

타입순서중복접근 방법
Array 있음 가능 index (0,1,2)
Dictionary 없음 key는 유일 key로 접근
Set 없음 불가능 값 자체

🧠 핵심 정리

  • Array → 순서 있는 리스트
  • Dictionary → 키-값 구조
  • Set → 중복 없는 집합

 

 

구조체로 되어있다(거의클래스)->제너릭

 

swift에서 array는 일반배열 or 빈배열를 만든다

상수let은 변경이 불가능함으로 변수var를 사용한다

주요예시

append로 접근하지 않고 값을 접근하면 값이 나오지 않음 

append는 값을 넣어라는 뜻

var number : [Int] = []

//빈 배열을 let으로 만들 수는 있지만 초기값에서 변경 불가이니 배열의 의미 없음

var odd = [Int]()

var even : Array<Int> = Array()

print(number) //[]

//print(number[0]) //오류, 빈 배열을 값을 넣은 다음에 접근

number.append(100) //let으로 선언한 불변형 배열이라 추가 불가능

//error: cannot use mutating member on immutable value: 'number' is a 'let' constant

print(number[0])

number.append(200)

print(number[0], number[1],number)

 

Array(repeating:count:)

배열의 여러개의 같은 값을 저장

 

=>Optional(1) Optional(4)

nil nil

1 4

첨자(subscript)로 항목 접근

 

 

 

 

sort원본을 변경 / aorted 잠시동안 변경 원본은 그대로 유지

 

append