ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • iOS 3주차
    iOS 2025. 9. 16. 16:38

    중간고사 나옴

    📌 튜플 값 추출

    • 한 줄 코드로 모든 값을 분해 가능:
     
    let myTuple = (10, 12.1, "Hi") let (myInt, myFloat, myString) = myTuple
    • myInt = 10, myFloat = 12.1, myString = "Hi"

    📌 특정 값 무시하기

    • 필요 없는 값은 밑줄(_) 로 무시:
     
    var (myInt, _, myString) = myTuple // 12.1은 무시됨

    📌 튜플 요소에 이름 붙이기

    • 각 값에 이름을 지정할 수 있음:
     
    let myTuple = (count: 10, length: 12.1, message: "Hi")
    • 접근 방법:
     
    print(myTuple.count) // 10 print(myTuple.message) // "Hi" print(myTuple.2) // "Hi" (인덱스로도 접근 가능)

    📌 함수에서의 활용

    • 튜플은 여러 값을 한 번에 반환할 때 매우 유용:
     
    func getUserInfo() -> (name: String, age: Int) { return ("수인", 24) } let user = getUserInfo() print(user.name) // "수인" print(user.age) // 24

    📌 Void와 빈 튜플

    • Void 는 빈 튜플( ) 과 동일
     
    typealias Void = () // 반환값이 없는 함수의 자료형 func doSomething() -> Void { print("Hello") }

    ✅ 요약:

    1. 튜플은 여러 값을 하나로 묶어서 쉽게 반환·저장할 수 있음
    2. 값 분해(Destructuring), 무시하기 _, 이름 붙이기 모두 가능
    3. 함수의 반환값 관리할 때 특히 강력함
    4. Void 는 사실 빈 튜플 ()

    시험에 가끔 나옴

     

     


     

    📌 옵션널 타입 강제 언래핑 (forced unwrapping)

    1. 옵션널(Optional)이란?

    • Swift에서 값이 있을 수도 있고 없을 수도 있는 변수를 표현할 때 사용.
    • 선언할 때 자료형 뒤에 ? 를 붙임.
     
    var x: Int? // 옵션널 정수형 변수 (값이 있을 수도, nil일 수도 있음) var y: Int = 0

    2. 옵션널 출력

     
    x = 10 print(x) // 출력: Optional(10)
    • 그냥 출력하면 Optional(10) 처럼 옵션널에 감싸진(wrapped) 형태로 표시됨.
    • 즉, 값이 10이라는 것을 알려주지만 "옵션널에 포장되어 있다"는 뜻.

    3. 강제 언래핑 (Forced Unwrapping)

     
    print(x!) // 출력: 10
    • 옵션널 변수 뒤에 ! 를 붙이면 강제로 포장(옵션널)을 벗김 → 실제 값 꺼내옴.
    • 이 과정을 강제 언래핑(forced unwrapping) 이라고 함.
    • 하지만 ⚠ 값이 nil 인데 !로 강제 언래핑하면 런타임 에러 발생 → 추천되는 방법은 아님.

    4. 주의사항 (연산 & 대입 불가)

     
    //x = x + 2 ❌ 오류 발생 //y = x ❌ 오류 발생
    • x는 Int? 타입이고, y는 Int 타입.
    • 옵션널을 그대로 연산하거나 일반 변수에 대입할 수 없음.
    • 언래핑(x!) 해서 Int 타입으로 변환한 뒤 사용해야 함.

    5. 정리 (슬라이드 핵심 포인트)

    • 옵셔널형 선언: 자료형 뒤 ?
    •  
      var num: Int?
    • 옵셔널 언래핑: 변수명 뒤 !
    •  
      print(num!)

    ✅ 결론:

    • Swift에서 ? → 값이 있을 수도 없을 수도 있는 타입
    • ! → 강제로 포장을 벗겨 실제 값 사용
    • 단, nil일 때 ! 쓰면 프로그램이 죽으므로 if let, guard let 같은 안전한 언래핑(optional binding) 방식을 쓰는 게 권장돼요.

     

    var x: Int?      // x는 Int? (옵셔널 Int) → 값이 있을 수도(nil일 수도) 있음
    var y: Int = 0   // y는 Int (무조건 값 있어야 함)

    x = 10           // ← 이 줄을 주석처리하면 x는 계속 nil 상태
    print(x)         // Optional(10) 출력 (또는 경고와 함께 Optional(10))
    print(x!)        // 강제 언래핑 → 10 출력 (nil이면 앱 크래시!)
    print(y)         // 0 출력

    // x = x + 2     // 에러: Int?와 Int는 바로 연산 불가
    // y = x         // 에러: Int?를 Int에 그냥 대입 불가

     

    1) Int?는 뭐고 왜 필요해?

    • Int?는 Optional<Int> 의 축약형이야.
      “정수값이 있을 수도, 없을 수도 있다”는 뜻.
    • 그래서 x에는 10도 들어갈 수 있고, nil도 들어갈 수 있어.

    비유: Int?는 상자 같은 것.
    상자 안에 숫자(10)가 들어있을 수도, 아예 빈 상자(nil)일 수도 있어.


    2) x = 10을 주석 처리하면?

    • x는 초기값이 없으니 기본값 nil.
    • print(x)는 nil을 출력(보통 nil 혹은 Optional(nil)처럼 보임).
    • print(x!)는 nil을 강제 언래핑하려 하므로
      👉 fatal error: unexpectedly found nil while unwrapping an Optional value 로 즉시 크래시.

    3) print(x)가 Optional(10)로 보이고, 경고가 뜨는 이유

    • print의 매개변수 타입은 Any라서, Int?를 그대로 넘기면 “옵셔널인 채로” 출력돼.
    • 그래서 Optional(10)처럼 감싼 형태로 보이는 거고,
    • 일부 환경에선 “Int?를 Any로 암시 변환했음” 경고가 뜰 수 있어.
      • 경고를 피하려면: print(x as Any)          // 경고 억제 (그냥 보여주기용)
        // 또는
        if let v = x { print(v) } // 안전 언래핑해서 Int로 출력

    4) print(x!)가 되는 이유와 위험성

    • !는 강제 언래핑: 상자를 “찢고” 안의 값을 무조건 꺼냄.
    • 값이 있으면 정상(10), nil이면 무조건 크래시라서 실무에선 지양.
    • 권장: 안전한 언래핑을 사용하자.
    • if let v = x { print(v) // x가 nil이 아닐 때만 v(Int) 사용 } else { print("값 없음") } // 혹은 기본값을 줄 수도 있음 print(x ?? 0) // x가 nil이면 0을 사용

    5) 왜 x = x + 2가 에러일까?

    • x는 Int?, 2는 Int.
      옵셔널과 일반값은 바로 연산할 수 없음. 먼저 언래핑해야 해.
    • 해결 방법:
    • // 1) if let if let v = x { x = v + 2 } // v는 Int, 계산 후 다시 x(Int?)에 대입 OK // 2) nil 병합 연산자 ?? x = (x ?? 0) + 2 // x가 nil이면 0으로 계산 → Int // Int를 Int?에 대입은 허용됨 // 3) guard let (함수/스코프 초기에 빠르게 탈출) func add2() { guard let v = x else { return } x = v + 2 }

    6) 왜 y = x가 에러일까?

    • y는 Int, x는 Int?.
      옵셔널을 일반 타입에 그냥 대입 불가.
    • 해결 방법:
    • // 1) 안전 언래핑 if let v = x { y = v } // 2) 기본값 사용 y = x ?? 0

    7) 정리 체크리스트

    • 옵셔널 선언: 자료형 뒤에 ? → var x: Int?
    • 강제 언래핑: 변수 뒤에 ! → x! (nil이면 크래시, 가급적 지양)
    • 권장 방식:
      • if let / guard let로 안전 언래핑
      • ??(nil 병합)으로 기본값 지정
    • 연산/대입 전엔 반드시 언래핑 해야 함.

    소스 이상할 때 정리하는 단축키

    ctrl + i

     

     

    시험에 잘냄

    📌 Optional Binding (옵셔널 바인딩)

    1. 왜 필요할까?

    • Int? 같은 옵셔널 변수는 값이 있을 수도 있고(nil일 수도 있고) 없을 수도 있음.
    • 그냥 !로 강제 언래핑하면 nil일 때 크래시 위험이 있음.
    • 👉 그래서 안전하게 꺼내는 방법이 옵셔널 바인딩.

    2. 기본 문법

     
    var x: Int? = 10 if let xx = x { print(x, xx) } else { print("nil") }

    동작:

    • if let xx = x :
      • x가 nil이 아니면 → 값을 언래핑해서 xx에 넣고 if문 실행.
      • x가 nil이면 → else 실행.

    👉 위 코드에서는 x = 10 이므로 xx = 10,
    출력 결과:

     
    Optional(10) 10

    3. Swift 5.7 이후 변화 (시험 포인트!!)

    • 기존: if let xx = x { … }
    • Swift 5.7부터: 짧게 if let x { … } 도 가능해짐.
    •  
      if let x { print(x) }
    • 👉 이걸 short form optional binding 이라고 부름.

    4. nil일 때 동작

     
    var x1: Int? // 기본값 nil if let xx = x1 { print(xx) // 실행 안 됨 } else { print("nil") // 실행됨 }

    출력 결과:

     
    nil

    5. 정리 (시험 대비 핵심)

    1. 옵셔널 바인딩: if let 또는 guard let 사용해서 nil 체크 + 값 언래핑 동시에 함.
    2. 강제 언래핑(!) 과 달리 안전함 → nil이면 else/early return 실행.
    3. Swift 5.7부터는 짧은 문법 지원: if let x { … }.
    4. 출력 예시 꼭 기억:
      • x = 10 → Optional(10) 10
      • x = nil → nil

    📌 코드 1

     
    var x : Int? // x는 "옵셔널 정수형" → 값이 있을 수도, 없을 수도 있음(nil 가능) x = 10 // x에 10을 대입 (즉, Optional(10))

    ✅ optional binding (옵셔널 바인딩)

     
    if let xx = x { print(x, xx) } else { print("nil") }
    • if let xx = x
      • x가 nil이 아니면 → x 안에 있던 실제 값을 꺼내서 xx라는 일반(Int) 상수에 넣음.
      • x가 nil이면 → 조건이 거짓이 되어 else로 이동.
    • 여기서는 x = 10 이므로 xx = 10
    • print(x, xx) →
      • x는 여전히 옵셔널 타입이라 Optional(10) 출력
      • xx는 일반 정수(Int)라서 10 출력

    👉 실행 결과:

     
    Optional(10) 10

    📌 코드 2

     
    var x1 : Int? // 옵셔널 정수형, 초기값 nil if let xx = x1 { print(xx) } else { print("nil") }
    • x1은 아무 값도 넣지 않았으므로 기본값 nil
    • if let xx = x1 실행 시:
      • x1이 nil → 조건이 거짓 → if문 블록 안 실행됨.
      • 따라서 else 블록 실행 → "nil" 출력

    👉 실행 결과:

     
    nil

    📌 정리

    • 옵셔널 바인딩 (if let / guard let):
      → 옵셔널이 nil이 아닐 때만 안전하게 값을 꺼내 쓸 수 있는 방법
    • print(x) : 옵셔널 그대로 찍으면 Optional(값) 형식
    • print(xx) : 옵셔널 바인딩으로 꺼낸 일반 값(Int) 출력

    ✅ 최종 출력 결과는:

     
    Optional(10) 10 nil
     
    시험 자주 냄

    📌 여러 옵셔널 언래핑

    1. 기본 코드

     
    var pet1: String? var pet2: String? pet1 = "cat" pet2 = "dog" if let firstPet = pet1, let secondPet = pet2 { print(firstPet, secondPet) } else { print("nil") }

    2. 동작 원리

    • if let firstPet = pet1, let secondPet = pet2
      콤마( , ) 를 사용하면 여러 옵셔널을 한 번에 바인딩 가능.
    • pet1, pet2 둘 다 nil이 아니면 → 값을 꺼내 각각 firstPet, secondPet에 대입.
    • 둘 중 하나라도 nil이면 → else 블록 실행.

    👉 여기서는 pet1 = "cat", pet2 = "dog" 이므로:
    출력 결과:

     
    cat dog

    3. Swift 5.7 이후 (short form)

    • 기존 문법:
    •  
      if let firstPet = pet1, let secondPet = pet2 { print(firstPet, secondPet) }
    • 단축 문법 (Swift 5.7+):
    •  
      if let pet1, let pet2 { print(pet1, pet2) }
    • 차이점:
      • 단축 문법에서는 firstPet, secondPet 같은 새로운 상수명을 안 만들어도 됨.
      • 그냥 원래 변수명(pet1, pet2)으로 언래핑된 값을 사용 가능.

    👉 즉, 위 코드를 short form으로 바꾸면:

     
    if let pet1, let pet2 { print(pet1, pet2) } else { print("nil") }

    4. 시험 대비 핵심 요약

    1. 여러 옵셔널 바인딩은 콤마( , ) 로 구분.
    2. 각각 let을 붙여야 함 (if let a = x, let b = y).
    3. Swift 5.7부터는 단축 문법 가능:
      • if let x { … }
      • if let x, let y { … }

    👉 교수님이 과제로 내신 건 “short form으로 바꾸기”니까, 답은:

     
    if let pet1, let pet2 {
        print(pet1, pet2)
    } else {
        print("nil")
    }
     
    옵셔널은 시험에 자주 냄
     

    📌 1. 옵셔널 변수 선언 (Optional Variable)

     
    var a: Int? // 옵셔널 정수형 변수 (값이 있을 수도, nil일 수도 있음) var b: Int // 일반 정수형 변수 (nil 불가)
    • Int? → 옵셔널 타입 (Optional<Int>)
      • 값이 있으면 정수 저장 (10)
      • 값이 없으면 nil 저장 가능
    • Int → 일반 정수
      • 반드시 값이 있어야 함 (0, 5, -3 등)
      • nil 불가능

    👉 비유:

    • Int = 숫자만 담는 투명 컵
    • Int? = 컵 + 뚜껑(뚜껑 열면 안에 물이 있을 수도 없을 수도 있음)

    📌 2. 강제 언래핑 (Forced Unwrapping)

     
    var x: Int? = 10 print(x) // Optional(10) print(x!) // 10
    • x는 옵셔널 → 그냥 출력하면 Optional(10)
    • x! 하면 → 강제로 뚜껑을 열고 안에 있는 값 꺼냄
    • ⚠️ 만약 x = nil인데 x! 하면 런타임 에러 발생
    •  
      fatal error: unexpectedly found nil while unwrapping an Optional value

    👉 강제 언래핑은 위험하기 때문에 추천되지 않음


    📌 3. 옵셔널 바인딩 (Optional Binding)

     
    var y: Int? = 10 if let value = y { print("값 있음:", value) } else { print("값 없음") }
    • if let value = y
      • y에 값이 있으면 → 언래핑해서 value에 대입 후 if문 실행
      • y가 nil이면 → else 실행

    👉 결과:

     
    값 있음: 10

    📌 4. Swift 5.7 이후 단축 문법 (Short Form)

     
    var z: Int? = 20 if let z { print("값 있음:", z) // 언래핑된 z } else { print("값 없음") }
    • 이전에는 반드시 if let temp = z 형식으로 새 상수(temp)를 만들어야 했음.
    • Swift 5.7부터는 그냥 if let z라고 쓰면 원래 변수명으로 언래핑된 값을 사용 가능.

    📌 5. 비교 정리 (시험 대비)

    구분문법특징위험성
    강제 언래핑 x! 옵셔널 값 강제로 꺼냄 nil이면 크래시 ⚠️
    안전 언래핑 (if-let) if let v = x { ... } nil 여부 체크 후 값 안전하게 사용 안전
    단축 문법 (5.7~) if let x { ... } 새 변수명 필요 없이 기존 변수명 사용 안전

    핵심 기억 포인트

    1. ? → 옵셔널(있을 수도, 없을 수도 있음)
    2. ! → 강제 언래핑 (조심해야 함, nil이면 죽음)
    3. if let → 안전하게 꺼내는 방법 (추천)
    4. Swift 5.7부터 if let x → 더 짧게 쓸 수 있음

    📌 1. 강제 언래핑 (Forced Unwrapping)

     
    var a: Int? = 10 print(a!) // ✅ 10 출력 a = nil print(a!) // ❌ 에러 발생 (fatal error: unexpectedly found nil)

    👉 값이 있으면 꺼내짐, 값이 없으면 프로그램 강제 종료.
    ⚠️ 실무에서 거의 안 씀.


    📌 2. 옵셔널 바인딩 (if-let)

     
    var b: Int? = 10 if let value = b { print("값 있음:", value) // ✅ "값 있음: 10" } else { print("값 없음") } b = nil if let value = b { print("값 있음:", value) } else { print("값 없음") // ✅ "값 없음" }

    👉 값이 있을 때만 안전하게 언래핑해서 if 블록 안에서 사용 가능.
    ⚡ 안전하고 가장 많이 쓰는 방법.


    📌 3. 옵셔널 바인딩 (Swift 5.7+ 단축 문법)

     
    var c: Int? = 20 if let c { print("값 있음:", c) // ✅ "값 있음: 20" } else { print("값 없음") } c = nil if let c { print("값 있음:", c) } else { print("값 없음") // ✅ "값 없음" }

    👉 새 변수명 필요 없이 원래 변수명(c)로 바로 언래핑 가능.
    (시험 포인트!)


    📌 4. nil 병합 연산자 (??) – 기본값 주기

     
    var d: Int? = nil print(d ?? 0) // ✅ 0 출력 (nil이면 0 사용) d = 50 print(d ?? 0) // ✅ 50 출력

    👉 옵셔널 값이 nil이면 기본값으로 대체할 때 유용.


    📌 최종 정리 (시험 대비 키워드)

    1. ? → 옵셔널 (있을 수도 없음)
    2. ! → 강제 언래핑 (위험)
    3. if let → 안전 언래핑 (권장)
    4. if let x (Swift 5.7~) → 단축 문법
    5. ?? → nil이면 기본값 사용

    // ─────────────────────────────
    // 1) 일반 Optional(Int?) 예제
    // ─────────────────────────────
    let x: Int? = 1          // x는 Optional<Int>. 값이 1이 '포장'되어 있음 (Some(1)/Optional(1))

    let y: Int = x!          // 강제 언래핑(!). x가 nil이 아니니까 1을 꺼내서 Int로 대입 (nil이면 크래시)
    let z = x                 // z의 타입은 추론으로 Optional<Int> (x와 동일한 옵셔널)

    print(x, y, z)            // 출력: Optional(1) 1 Optional(1)
    //  - x, z는 Optional이라 그대로 찍으면 Optional(1)로 보임
    //  - y는 Int라서 1

    print(type(of: x), type(of: y), type(of: z))
    // 출력: Optional<Int> Int Optional<Int>
    //  - x, z는 Optional<Int>, y는 Int


    // ─────────────────────────────
    // 2) IUO(Implicitly Unwrapped Optional, Int!) 예제
    // ─────────────────────────────
    let a: Int! = 1           // a는 '암시적 추출 옵셔널'. 내부적으로는 Optional<Int>와 같음
                              // 차이: 필요한 상황에서 '자동으로' 언래핑되어 Int처럼 써짐

    let b: Int = a            // 기대 타입이 Int이므로 '자동 언래핑'되어 1이 대입됨
    let c: Int = a!           // 물론 직접 !로 강제 언래핑해도 동일하게 1

    let d = a                 // 기대 타입이 정해지지 않았으므로 Optional로 취급 → d는 Optional<Int>
    let e = a + 1             // 산술 연산(+)은 Int가 필요 → a가 자동 언래핑되어 1 + 1 = 2 (a가 nil이면 여기서 크래시)

    print(a, b, c, d, e)      // 출력: Optional(1) 1 1 Optional(1) 2
    //  - 왜 a가 Optional(1)로 찍힐까? print의 매개변수 타입이 Any라서
    //    IUO도 이 컨텍스트에선 Optional로 '보여'주기 때문.
    //  - b, c, e는 Int로 사용되어 각각 1, 1, 2
    //  - d는 Optional이라 Optional(1)

    print(type(of: a), type(of: b), type(of: c), type(of: d), type(of: e))
    // 출력: Optional<Int> Int Int Optional<Int> Int
    //  - a와 d는 Optional<Int>, 나머지는 Int

     

    핵심 정리 (시험용 포인트)

    • Int?와 Int!는 둘 다 옵셔널이다 → nil을 가질 수 있다.
    • Int?는 항상 직접 언래핑이 필요 (if let/guard let 권장, ! 지양).
    • Int!(IUO)는 컨텍스트에 따라 자동 언래핑:
      • Int가 필요한 자리(대입, 산술 연산 등) → 자동으로 Int로 풀림.
      • 그 외(예: print의 Any 파라미터, 타입 추론이 애매한 자리) → Optional로 남음.
    • 위험성: Int!가 nil인데 자동/강제 언래핑이 일어나면 런타임 크래시.
      • let e = a + 1 처럼 연산에 들어가는 순간 nil이면 바로 터진다.
    • 안전한 습관: IUO는 IBOutlet처럼 “초기에 nil이지만 사용 시점에는 반드시 값이 있다”가 보장될 때만.
      일반 로직에선 Int? + if let/guard let 또는 ??(기본값) 사용이 정석.

    📌 옵셔널 요약 정리 (시험 대비)

    구분Int? (옵셔널)Int! (암시적 추출 옵셔널, IUO)
    선언 var x: Int? var y: Int!
    공통점 둘 다 Optional 타입, nil 가능 둘 다 Optional 타입, nil 가능
    값 꺼내기 x! 강제 언래핑 필요
    if let, guard let으로 안전 언래핑
    자동 언래핑: Int가 필요한 상황이면 바로 풀림
    직접 y! 강제 언래핑도 가능
    출력 print(x) → Optional(10) print(y) → Optional(10) (Any 타입으로 변환돼 Optional로 보임)
    연산 x + 1 ❌ (언래핑해야 가능) y + 1 ✅ (자동 언래핑)
    타입 추론 let z = x → Optional<Int> let d = y → Optional<Int> (맥락에 따라 달라짐)
    안전성 안전 (언래핑 여부를 코드로 명시) 위험 (nil이면 자동 언래핑 시 런타임 에러)
    사용 예 일반 변수 대부분 IBOutlet, “반드시 값이 채워질 것”이 보장된 경우

    📌 핵심 문장 (서술형 대비)

    • Int?와 Int!는 모두 옵셔널 타입으로 nil을 저장할 수 있다.
    • 차이는 Int?는 값을 꺼낼 때 반드시 언래핑이 필요하지만, Int!는 Int가 필요한 상황에서 자동 언래핑이 일어난다는 점이다.
    • 단, Int!가 nil일 때 자동 언래핑되면 런타임 에러가 발생하므로, 안전성 측면에서는 Int? + 옵셔널 바인딩(if let / guard let)을 쓰는 것이 권장된다.
    • Int!는 주로 스토리보드 IBOutlet처럼 “초기에는 nil이지만 사용 시점에는 반드시 값이 있음”이 보장된 상황에서만 사용한다.

     


    옵셔널 끝 연산자 시작

    시험

    📌 nil-coalescing operator (??)

    1. 의미

    • 문법:
    •  
      옵셔널변수 ?? 기본값
    • 동작 원리:
      • 옵셔널이 nil이면 → ?? 뒤의 값 사용
      • 옵셔널이 nil이 아니면 → 언래핑된 실제 값 사용

    2. 코드 예제와 결과

     
    let defaultAge = 1 var age: Int? age = 3 print(age) // Optional(3)
    • age는 옵셔널이고 값이 3이 들어있음 → 출력: Optional(3)
     
    var myAge = age ?? defaultAge print(myAge) // 3
    • age가 nil이 아니므로 언래핑된 값 3이 들어감.
    • 만약 age = nil이었다면 myAge = defaultAge → 1이 들어갔을 것.

    ✅ 과제 답

    • print(age) → Optional(3)
    • print(myAge) → 3

    3. 다른 예제

     
    var x: Int? = 1 var y = x ?? 0 print(y) // 1
    • x는 Optional(1) → nil 아님
    • 따라서 y = 1
    • 만약 x = nil이었다면 y = 0

    📌 시험 대비 핵심 요약

    1. ?? 연산자는 옵셔널이 nil일 때 기본값을 대입하는 연산자.
    2. 옵셔널 ?? 값
      • 옵셔널이 nil이면 ?? 뒤 값 사용
      • 옵셔널이 nil이 아니면 옵셔널 값 언래핑해서 사용
    3. 자주 쓰이는 패턴:→ inputName이 nil이면 "Unknown"이 들어가고, 값이 있으면 그 값 사용.
    4.  
      let name = inputName ?? "Unknown"

     

    'iOS' 카테고리의 다른 글

    iOS 7주차  (0) 2025.10.14
    5주차  (0) 2025.09.30
    4주차  (0) 2025.09.23
    iOS 2주차  (0) 2025.09.09
    iOS 1  (2) 2025.09.02
Designed by Tistory.