ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • iOS 2주차
    iOS 2025. 9. 9. 15:18

     

     

    무슨 파일?

    • GameViewController.swift는 초기 화면에 SpriteKit의 씬(GameScene) 을 로드하고 보여주는 뷰 컨트롤러입니다.
    • 내부적으로 SKView로 캐스팅한 뒤, FPS·노드 수 표시, 렌더링 최적화 옵션(ignoresSiblingOrder) 등을 켭니다.

    기존 코드의 아쉬운 점

    1. 구식 로딩 방식
      • NSKeyedUnarchiver로 .sks를 직접 언아카이브하는 확장(Extension)을 사용합니다.
      • 현재는 SKScene(fileNamed:) 로 간단하고 안전하게 로드하는 게 일반적입니다.
    2. 강제 언래핑(!) 남용
      • 파일 경로/데이터/캐스팅에 !가 많아 런타임 크래시 위험이 큽니다.
      • guard let을 써서 안전하게 처리하는 게 좋아요.
    3. 타입 캐스팅 강제
      • let skView = self.view as! SKView → 실패 시 크래시. 안전 캐스팅 권장.
    4. 불필요/구식 메서드
      • didReceiveMemoryWarning()은 현대 iOS에서는 의미가 거의 없고 잘 안 씁니다. 빼도 무방.
    5. 매직 넘버/옵션 분산
      • 디버그 옵션(FPS/노드수 표시)을 상수로 빼면 의도가 더 선명해집니다.

    리팩터링 목표

    • SKScene(fileNamed:) 활용: 간결 + 안정성
    • guard let로 안전하게 언래핑
    • 강제 캐스팅 최소화 (as?)
    • 옵션/상수 정리로 의도 드러내기
    • 한국어 주석으로 흐름 설명

    리팩터링된 코드 (주석 포함)

     
    // // GameViewController.swift // FlappyBird // // 참고: 현대 SpriteKit에선 .sks 로드는 NSKeyedUnarchiver 대신 // SKScene(fileNamed:)를 사용하는 것이 간결하고 안전합니다. // import UIKit import SpriteKit final class GameViewController: UIViewController { // 디버그용 표시를 한 곳에서 관리 (의도가 드러나도록) private let showsDebugInfo: Bool = true override func viewDidLoad() { super.viewDidLoad() // 1) 현재 뷰가 SpriteKit을 렌더링할 수 있는 SKView인지 안전하게 확인 guard let skView = self.view as? SKView else { assertionFailure("현재 뷰가 SKView가 아닙니다. Main.storyboard에서 View의 클래스가 SKView인지 확인하세요.") return } // 2) GameScene.sks 로드 (파일 이름과 확장자 .sks는 Xcode 내 리소스) // - 실패하면 리턴하여 크래시를 피합니다. guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else { assertionFailure("GameScene.sks 로드 실패 혹은 타입 캐스팅 실패. 파일명과 클래스 연결 확인!") return } // 3) 렌더링/디버그 설정 skView.showsFPS = showsDebugInfo skView.showsNodeCount = showsDebugInfo // 형제 노드 간 Z-정렬 최적화: 일반적으로 켜두면 성능에 유리 skView.ignoresSiblingOrder = true // 4) 씬의 스케일 모드: 기기 화면 비율에 맞게 채움 scene.scaleMode = .aspectFill // 5) 씬을 화면에 표시 skView.presentScene(scene) } // 기기 회전 허용 여부 override var shouldAutorotate: Bool { return true } // 지원하는 회전 방향(아이폰/아이패드 분기) override var supportedInterfaceOrientations: UIInterfaceOrientationMask { if UIDevice.current.userInterfaceIdiom == .phone { return .allButUpsideDown } else { return .all } } // 상태바 노출 여부 (게임은 가려두는 경우가 많음) — 필요 시 조정 override var prefersStatusBarHidden: Bool { return true } }

    추가 팁

    • 스토리보드/SwiftUI 구성 확인: ViewController의 루트 뷰를 SKView로 설정해야 as? SKView가 성공합니다.
    • GameScene.swift / GameScene.sks 연결: .sks 파일의 Custom Class가 GameScene인지 확인하세요.
    • 좌표/물리디버그: 필요하면 skView.showsPhysics = true로 물리 바운더리 확인이 가능합니다.
    • 크래시 방지: assertionFailure는 디버그에서만 멈추고, 릴리즈에선 무시됩니다. 사용자에게는 치명적 크래시를 피하고, 개발 중엔 빠르게 문제를 알게 해줍니다.

    //
    //  GameViewController.swift
    //  FlappyBird
    //
    //  참고: 현대 SpriteKit에선 .sks 로드는 NSKeyedUnarchiver 대신
    //        SKScene(fileNamed:)를 사용하는 것이 간결하고 안전합니다.
    //

    import UIKit
    import SpriteKit

    final class GameViewController: UIViewController {
        
        // 디버그용 표시를 한 곳에서 관리 (의도가 드러나도록)
        private let showsDebugInfo: Bool = true
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // 1) 현재 뷰가 SpriteKit을 렌더링할 수 있는 SKView인지 안전하게 확인
            guard let skView = self.view as? SKView else {
                assertionFailure("현재 뷰가 SKView가 아닙니다. Main.storyboard에서 View의 클래스가 SKView인지 확인하세요.")
                return
            }
            
            // 2) GameScene.sks 로드 (파일 이름과 확장자 .sks는 Xcode 내 리소스)
            //    - 실패하면 리턴하여 크래시를 피합니다.
            guard let scene = SKScene(fileNamed: "GameScene") as? GameScene else {
                assertionFailure("GameScene.sks 로드 실패 혹은 타입 캐스팅 실패. 파일명과 클래스 연결 확인!")
                return
            }
            
            // 3) 렌더링/디버그 설정
            skView.showsFPS = showsDebugInfo
            skView.showsNodeCount = showsDebugInfo
            
            // 형제 노드 간 Z-정렬 최적화: 일반적으로 켜두면 성능에 유리
            skView.ignoresSiblingOrder = true
            
            // 4) 씬의 스케일 모드: 기기 화면 비율에 맞게 채움
            scene.scaleMode = .aspectFill
            
            // 5) 씬을 화면에 표시
            skView.presentScene(scene)
        }
        
        // 기기 회전 허용 여부
        override var shouldAutorotate: Bool {
            return true
        }
        
        // 지원하는 회전 방향(아이폰/아이패드 분기)
        override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
            if UIDevice.current.userInterfaceIdiom == .phone {
                return .allButUpsideDown
            } else {
                return .all
            }
        }
        
        // 상태바 노출 여부 (게임은 가려두는 경우가 많음) — 필요 시 조정
        override var prefersStatusBarHidden: Bool {
            return true
        }
    }

     


    raywenderlich.com의 Swift 스타일가이드

    https://github.com/swift-kr/swift-style-guide-raywenderlich/blob/master/ko_style_guide.md

     

    swift-style-guide-raywenderlich/ko_style_guide.md at master · swift-kr/swift-style-guide-raywenderlich

    The official Swift style guide for raywenderlich.com. - swift-kr/swift-style-guide-raywenderlich

    github.com

    Swift 문법 실습

    https://www.onlinegdb.com/online_swift_compiler

    https://www.programiz.com/swift/online-compiler/

    https://swiftfiddle.com/ : 가장 최근 버전도 지원

     

     

    스위프트에서 데이터 타입(Data Type) 은 “값의 종류”를 정의하는 개념이에요.
    즉, 정수인지, 소수인지, 문자열인지, 참/거짓인지에 따라 다르게 다루어야 해서, 타입을 명확히 구분합니다.
    대표적인 타입을 예시와 함께 정리해 드릴게요.


    1. 정수형 (Int, UInt)

    • Int : 정수 (음수/양수 모두 가능)
    • UInt : 부호 없는 정수 (0과 양수만 가능)

    let age: Int = 24      // 정수 (예: 나이)
    let coins: UInt = 100  // 음수가 될 수 없는 값 (예: 동전 개수)

    2. 실수형 (Double, Float)

    • Double : 64비트 실수 (더 정밀, 보통 이거 사용)
    • Float : 32비트 실수 (메모리 적게 쓰지만 정밀도 낮음)
     
    let pi: Double = 3.1415926535 let temperature: Float = 36.5

    3. 문자와 문자열 (Character, String)

    • Character : 한 글자
    • String : 여러 글자(문자열)
     
    let grade: Character = "A" let name: String = "문수인"

    4. 불리언 (Bool)

    • 참/거짓을 나타내는 타입
     
    let isGameOver: Bool = false let isLogin: Bool = true

    5. 컬렉션 타입

    스위프트에서 데이터를 묶어서 다루는 3가지 기본 타입이 있어요.

    (1) 배열 Array

    • 순서가 있는 값들의 집합
     
    let numbers: [Int] = [1, 2, 3, 4, 5] print(numbers[0]) // 1

    (2) 집합 Set

    • 순서가 없고, 중복을 허용하지 않는 집합
     
    let colors: Set<String> = ["Red", "Blue", "Green", "Red"] print(colors) // {"Blue", "Red", "Green"} (중복 자동 제거)

    (3) 딕셔너리 Dictionary

    • 키 : 값 형태의 자료 구조
     
    let student: [String: Any] = [ "name": "수인", "age": 24, "major": "컴퓨터소프트웨어학과" ] print(student["name"]!) // "수인"

    6. 옵셔널 (Optional)

    • 값이 있을 수도 있고 없을 수도 있는 타입 (nil 허용)
    • 스위프트의 중요한 개념
     
    var nickname: String? = nil // 아직 값 없음 nickname = "뚜벅이" print(nickname) // Optional("뚜벅이") print(nickname!) // "뚜벅이" (강제 언래핑, 값이 없으면 에러)

    7. 타입 추론

    • 스위프트는 타입을 생략해도 자동으로 추론해 줍니다.
     
    let score = 95 // Int로 추론 let ratio = 0.75 // Double로 추론 let message = "안녕" // String으로 추론

    👉 정리하면,
    스위프트는 타입 안전성(type safety) 을 중요시해서 값의 종류를 명확히 구분해요.
    그래서 Int, Double, String, Bool, Array, Dictionary, Optional 같은 타입을 통해 안정적으로 데이터를 다룰 수 있습니다.


     

     

    스위프트의 print() 함수는 콘솔(터미널, 디버그 창)에 텍스트를 출력할 때 쓰는 기본 함수예요.
    하나씩 예시와 함께 설명해 드릴게요.


    1. 기본 사용

     
    print("안녕하세요")

    👉 콘솔에

     
    안녕하세요

    라고 출력됩니다.


    2. 여러 값 출력

    print() 안에 여러 값을 콤마( , )로 나열하면, 자동으로 띄어쓰기를 해 줍니다.

     
    let name = "수인" let age = 24 print("이름:", name, "나이:", age)

    👉 출력:

     
    이름: 수인 나이: 24

    3. 문자열 보간법 (String Interpolation)

    스위프트에서 자주 쓰는 방식.
    문자열 안에 \(변수) 형태로 값을 넣습니다.

     
    let score = 95 print("시험 점수는 \(score)점 입니다.")

    👉 출력:

     
    시험 점수는 95점 입니다.

    4. 줄바꿈 없애기 (terminator)

    기본적으로 print()는 출력 후 자동으로 줄바꿈(\n) 을 해요.
    terminator 파라미터로 바꿀 수 있습니다.

     
    print("Hello", terminator: " ") print("World")

    👉 출력:

     
    Hello World

    5. 구분자 바꾸기 (separator)

    여러 값을 출력할 때, 기본 구분자는 공백(" ") 입니다.
    separator 파라미터로 원하는 걸 넣을 수 있어요.

     
    print(1, 2, 3, 4, 5, separator: "-")

    👉 출력:

     
    1-2-3-4-5

    6. 디버깅 전용 dump()

    print() 대신 **dump()**를 쓰면, 객체의 속성까지 자세히 보여줍니다.

     
    struct Student { let name: String let age: Int } let student = Student(name: "문수인", age: 24) print(student) // 단순 출력 dump(student) // 속성까지 구조적으로 출력

    👉 출력:

     
    Student(name: "문수인", age: 24) // print() ▿ Student // dump() - name: "문수인" - age: 24

    ✅ 정리하면

    • print() → 콘솔에 값 출력 (separator, terminator로 조절 가능)
    • 문자열 보간법 → "\(변수)" 방식으로 값 삽입
    • dump() → 객체의 상세 구조 출력

    스위프트의 print() 함수는 콘솔(터미널, 디버그 창)에 텍스트를 출력할 때 쓰는 기본 함수예요.
    하나씩 예시와 함께 설명해 드릴게요.


    1. 기본 사용

     
    print("안녕하세요")

    👉 콘솔에

     
    안녕하세요

    라고 출력됩니다.


    2. 여러 값 출력

    print() 안에 여러 값을 콤마( , )로 나열하면, 자동으로 띄어쓰기를 해 줍니다.

     
    let name = "수인" let age = 24 print("이름:", name, "나이:", age)

    👉 출력:

     
    이름: 수인 나이: 24

    3. 문자열 보간법 (String Interpolation)

    스위프트에서 자주 쓰는 방식.
    문자열 안에 \(변수) 형태로 값을 넣습니다.

     
    let score = 95 print("시험 점수는 \(score)점 입니다.")

    👉 출력:

     
    시험 점수는 95점 입니다.

    4. 줄바꿈 없애기 (terminator)

    기본적으로 print()는 출력 후 자동으로 줄바꿈(\n) 을 해요.
    terminator 파라미터로 바꿀 수 있습니다.

     
    print("Hello", terminator: " ") print("World")

    👉 출력:

     
    Hello World

    5. 구분자 바꾸기 (separator)

    여러 값을 출력할 때, 기본 구분자는 공백(" ") 입니다.
    separator 파라미터로 원하는 걸 넣을 수 있어요.

     
    print(1, 2, 3, 4, 5, separator: "-")

    👉 출력:

     
    1-2-3-4-5

    6. 디버깅 전용 dump()

    print() 대신 **dump()**를 쓰면, 객체의 속성까지 자세히 보여줍니다.

     
    struct Student { let name: String let age: Int } let student = Student(name: "문수인", age: 24) print(student) // 단순 출력 dump(student) // 속성까지 구조적으로 출력

    👉 출력:

     
    Student(name: "문수인", age: 24) // print() ▿ Student // dump() - name: "문수인" - age: 24

    ✅ 정리하면

    • print() → 콘솔에 값 출력 (separator, terminator로 조절 가능)
    • 문자열 보간법 → "\(변수)" 방식으로 값 삽입
    • dump() → 객체의 상세 구조 출력

    스위프트의 print() 함수는 콘솔(터미널, 디버그 창)에 텍스트를 출력할 때 쓰는 기본 함수예요.
    하나씩 예시와 함께 설명해 드릴게요.


    1. 기본 사용

     
    print("안녕하세요")

    👉 콘솔에

     
    안녕하세요

    라고 출력됩니다.


    2. 여러 값 출력

    print() 안에 여러 값을 콤마( , )로 나열하면, 자동으로 띄어쓰기를 해 줍니다.

     
    let name = "수인" let age = 24 print("이름:", name, "나이:", age)

    👉 출력:

     
    이름: 수인 나이: 24

    3. 문자열 보간법 (String Interpolation)

    스위프트에서 자주 쓰는 방식.
    문자열 안에 \(변수) 형태로 값을 넣습니다.

     
    let score = 95 print("시험 점수는 \(score)점 입니다.")

    👉 출력:

     
    시험 점수는 95점 입니다.

    4. 줄바꿈 없애기 (terminator)

    기본적으로 print()는 출력 후 자동으로 줄바꿈(\n) 을 해요.
    terminator 파라미터로 바꿀 수 있습니다.

     
    print("Hello", terminator: " ") print("World")

    👉 출력:

     
    Hello World

    5. 구분자 바꾸기 (separator)

    여러 값을 출력할 때, 기본 구분자는 공백(" ") 입니다.
    separator 파라미터로 원하는 걸 넣을 수 있어요.

     
    print(1, 2, 3, 4, 5, separator: "-")

    👉 출력:

     
    1-2-3-4-5

    6. 디버깅 전용 dump()

    print() 대신 **dump()**를 쓰면, 객체의 속성까지 자세히 보여줍니다.

     
    struct Student { let name: String let age: Int } let student = Student(name: "문수인", age: 24) print(student) // 단순 출력 dump(student) // 속성까지 구조적으로 출력

    👉 출력:

     
    Student(name: "문수인", age: 24) // print() ▿ Student // dump() - name: "문수인" - age: 24

    ✅ 정리하면

    • print() → 콘솔에 값 출력 (separator, terminator로 조절 가능)
    • 문자열 보간법 → "\(변수)" 방식으로 값 삽입
    • dump() → 객체의 상세 구조 출력

    import Foundation

    // print 함수 기본 형태
    // func print(_ items: Any..., separator: String = " ", terminator: String = "\n")

    // 문자열 출력
    print("안녕")

    // 정수 출력
    print(123)

    // 변수 출력
    var age = 20
    var name = "Smile"

    print(age)
    print(age, name)                     // 여러 값 출력 (기본은 공백으로 구분)

    // 문자열 보간 (String Interpolation)
    print("나이는 \(age)입니다")

    // 여러 정수 출력
    print(1, 2, 3)                       // 기본: 공백으로 구분
    print(1, 2, 3, separator: "-")       // 구분자 변경 → 1-2-3

    // 줄바꿈(terminator) 활용
    print("Smile")
    print("Han")

    print("Hello", terminator: " ")      // 줄바꿈 대신 공백으로 마무리
    print("World!")                      // → Hello World!

    print("다음", terminator: "")        // 아무것도 붙이지 않음
    print("입니다.")                     // → 다음입니다.

     

    1. var vs let 기본 차이

    • var : 값을 변경할 수 있는 변수(variable)
    • let : 한 번 정하면 바꿀 수 없는 상수(constant)
     
    var age = 20 age = 21 // ✅ 변경 가능 let name = "수인" // name = "홍길동" // ❌ 오류! let은 값 변경 불가

    2. 왜 let을 권장할까?

    ✅ (1) 안전성

    • let은 값이 절대 바뀌지 않음을 보장해 줍니다.
    • 코드 읽는 사람이 “이 값은 고정값이구나” 하고 믿고 쓸 수 있어요.
    • 실수로 값이 바뀌는 버그를 미리 차단할 수 있습니다.

    ✅ (2) 최적화

    • 컴파일러가 let을 쓰면 내부적으로 “이건 변하지 않는 값”이라고 판단해서 최적화를 더 잘 할 수 있습니다.
    • 예: 메모리 관리나 속도 면에서 더 효율적으로 동작할 수 있음.

    ✅ (3) 코드 가독성 & 의도 표현

    • var는 “나중에 바뀔 수 있음”
    • let은 “절대 안 바뀜”
      → 선언만 봐도 개발자의 의도가 드러납니다.
     
    let pi = 3.14159 // 절대 바뀌지 않는 값 var score = 0 // 게임하면서 바뀌는 값

    ✅ (4) 함수형 프로그래밍 철학과 어울림

    • Swift는 함수형 프로그래밍 개념을 많이 차용했는데,
      함수형 프로그래밍에서는 불변성(immutability) 을 강조합니다.
    • 즉, 상태(state)가 자꾸 바뀌면 예측하기 어려운 버그가 생기는데,
      let을 쓰면 상태 변화를 줄일 수 있어요.

    3. 결론

    • 기본적으로는 무조건 let을 쓰고,
    • 정말 값이 변해야 할 때만 var로 바꾸는 습관이 좋아요.

    👉 “변경될 필요가 없다면 let!
    👉 “불가피하게 바뀌어야 한다면 var!

    'iOS' 카테고리의 다른 글

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