-


무슨 파일?
- GameViewController.swift는 초기 화면에 SpriteKit의 씬(GameScene) 을 로드하고 보여주는 뷰 컨트롤러입니다.
- 내부적으로 SKView로 캐스팅한 뒤, FPS·노드 수 표시, 렌더링 최적화 옵션(ignoresSiblingOrder) 등을 켭니다.
기존 코드의 아쉬운 점
- 구식 로딩 방식
- NSKeyedUnarchiver로 .sks를 직접 언아카이브하는 확장(Extension)을 사용합니다.
- 현재는 SKScene(fileNamed:) 로 간단하고 안전하게 로드하는 게 일반적입니다.
- 강제 언래핑(!) 남용
- 파일 경로/데이터/캐스팅에 !가 많아 런타임 크래시 위험이 큽니다.
- guard let을 써서 안전하게 처리하는 게 좋아요.
- 타입 캐스팅 강제
- let skView = self.view as! SKView → 실패 시 크래시. 안전 캐스팅 권장.
- 불필요/구식 메서드
- didReceiveMemoryWarning()은 현대 iOS에서는 의미가 거의 없고 잘 안 씁니다. 빼도 무방.
- 매직 넘버/옵션 분산
- 디버그 옵션(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!”