본문 바로가기
iOS

Xcode에서 겪게 되는 기초 문법 정리

by Hwangminseo 2025. 9. 9.

본격적인 문법 학습에 앞서 macOS에서 iOS 시뮬레이터를 먼저 실행해 본다.
실행·빌드·로그 확인 등 기본 흐름을 간단한 예제로 확인한다.
예제는 Flappy Bird를 사용해 화면 표시와 입력 반응을 알아볼 것이다.

Flappy Bird

  • 출시일: 2013년
  • 플랫폼: iOS, Android
  • 장르: 아케이드 / 캐주얼
  • 엔진: 초기 개발은 Cocos2d-x 사용

게임 방식

  • 화면을 터치하면 새(Flappy)가 위로 날아오르고, 터치를 멈추면 중력에 의해 아래로 떨어진다.
  • 파이프 사이의 좁은 틈을 통과할 때마다 점수가 올라간다.
  • 규칙은 단순하지만, 난이도가 매우 높아 중독성과 좌절감을 동시에 주는 것이 특징이다.

 

//  GameViewController.swift
//  FlappyBird
//  Created by Nate Murray on 6/2/14.
//  Copyright (c) 2014 Fullstack.io. All rights reserved.
import UIKit      // iOS 기본 UI 라이브러리 (화면, 버튼 등)
import SpriteKit  // 2D 게임 엔진 라이브러리 (애플 제공)
// MARK: - SKNode 확장 (sks 파일에서 씬 불러오기 기능 추가)
extension SKNode {
    class func unarchiveFromFile(_ file : String) -> SKNode? {
        
        // 앱 번들 안에서 "file.sks" 파일의 경로 찾기
        let path = Bundle.main.path(forResource: file, ofType: "sks")
        
        // 씬 데이터를 저장할 변수
        let sceneData: Data?
        do {
            // 파일 경로를 이용해 Data 타입으로 읽어오기 (옵션: 안전한 메모리 매핑)
            sceneData = try Data(contentsOf: URL(fileURLWithPath: path!), options: .mappedIfSafe)
        } catch _ {
            // 만약 파일을 못 읽으면 nil 처리
            sceneData = nil
        }
        
        // 읽은 Data를 실제 객체로 복원하기 위해 아카이브 해제 도구 생성
        let archiver = NSKeyedUnarchiver(forReadingWith: sceneData!)
        
        // "SKScene"이라고 저장된 데이터를 실제 GameScene 클래스에 연결
        archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
        
        // 아카이브 데이터를 GameScene 객체로 변환
        let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! GameScene
        
        // 변환 완료 → 마무리
        archiver.finishDecoding()
        
        // GameScene 객체 반환
        return scene
    }
}
// MARK: - 게임 화면을 담당하는 뷰 컨트롤러
class GameViewController: UIViewController {
    // 화면이 처음 로드될 때 실행됨
    override func viewDidLoad() {
        super.viewDidLoad()
        // GameScene.sks 파일을 불러와 GameScene 객체로 변환
        if let scene = GameScene.unarchiveFromFile("GameScene") as? GameScene {
            
            // 현재 뷰를 SpriteKit 전용 뷰(SKView)로 캐스팅
            let skView = self.view as! SKView
            
            // 디버깅용: 초당 프레임 수(FPS) 표시
            skView.showsFPS = true
            
            // 디버깅용: 현재 화면에 있는 노드 개수 표시
            skView.showsNodeCount = true
            
            // 형제 노드 순서를 자동 최적화 (성능 향상)
            skView.ignoresSiblingOrder = true
            
            // 씬 크기를 화면에 맞게 스케일 (비율 유지 + 화면 채우기)
            scene.scaleMode = .aspectFill
            
            // 준비된 씬을 화면에 표시
            skView.presentScene(scene)
        }
    }
    // 화면 회전을 허용할지 여부
    override var shouldAutorotate : Bool {
        return true
    }
    // 지원하는 화면 방향 지정 (기기별로 다름)
    override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
        if UIDevice.current.userInterfaceIdiom == .phone {
            // 아이폰은 거꾸로 방향(업사이드다운)만 금지
            return UIInterfaceOrientationMask.allButUpsideDown
        } else {
            // 아이패드는 모든 방향 허용
            return UIInterfaceOrientationMask.all
        }
    }
    // 메모리 부족 시 호출 → 불필요한 리소스 정리
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // 예: 캐시된 이미지, 데이터 해제
    }
}

 

Windows·Linux 등 macOS가 아닌 환경에서도 Swift 코드를 작성하고 실행하게 하기 위해선
브라우저 기반 실행 환경을 제공해 설치 없이 즉시 실험을 시작하게 한다.
최신 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 스타일 가이드의 한국어 번역본으로, Swift 코드를 명확하고 일관되게 작성하는 기준을 제시한다.
네이밍, 공백·들여 쓰기, 함수·클로저 선언, 접근 제어, 옵셔널·컬렉션 처리 등 실무 규칙을 체계적으로 정리한다.
SwiftLint 연동과 예시를 통해 팀 협업과 코드 리뷰 품질을 높이는 데 기여한다.

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

 

Online Swift Compiler - Programiz

Write and run your Swift code using our online compiler. Enjoy additional features like code sharing, dark mode, and support for multiple programming languages.

www.programiz.com

브라우저에서 Swift 코드를 작성하고 실행하여 결과를 즉시 확인하게 한다.
실행·출력 패널과 함께 링크 복사 등 코드 공유 기능을 제공한다.
기본 main.swift 템플릿과 Run 버튼으로 빠르게 테스트를 시작하게 한다.

https://swiftfiddle.com/

 

Swift Online Playground

SwiftFiddle is an online playground for creating, sharing and embedding Swift fiddles (little Swift programs that run directly in your browser).

swiftfiddle.com

브라우저에서 Swift 코드를 작성·실행·공유하게 한다.
최신 Swift 버전 반영이 빠르며, 나이틀리·베타 채널까지 선택해 새 기능을 즉시 시험하게 한다.
Swift Algorithms·Collections·Crypto 등 주요 SPM 패키지를 내장해 import만으로 실험을 시작하게 한다.

Xcode Playground 화면으로 import UIKit, var greeting = "Hello, playground", print(greeting) 코드를 작성한다.
우측 Quick Look 패널이 즉시 평가 결과를 보여주며, 상단의 실행 버튼(▷)으로 코드를 실행한다.
하단 콘솔에 Hello, playground 출력이 기록되어 실제 실행 결과를 확인하게 한다.

🔹 Swift 언어 데이터 타입

1) 정수형 (Int, UInt)

  • 정수 값을 표현한다.
  • Int는 음수·양수·0을, UInt는 0 이상만 허용한다.
  • 플랫폼에 따라 비트 폭이 달라질 수 있으나 보통 64비트를 사용한다.
let age: Int = 23
let studentCount: UInt = 30

2) 실수형 (Double, Float)

  • 부동소수점 실수 값을 표현한다.
  • Double은 64비트로 더 정밀하고, Float은 32비트로 메모리를 아낀다.
  • 계산 정확도가 중요하면 Double을 기본으로 사용한다.
let pi: Double = 3.1415926535
let height: Float = 175.5

3) 문자 (Character)

  • 유니코드 문자 1개(확장 그래프 클러스터)를 표현한다.
  • 단일 글자뿐 아니라 이모지·조합 문자도 정확히 다룬다.
  • 큰따옴표 문자열에서 한 글자 단위로 취급한다.
let grade: Character = "A"
let symbol: Character = "🙂"

4) 문자열 (String)

  • 유니코드 텍스트를 표현하는 값 타입이다.
  • 복사-온-라이트(Copy-on-Write)로 성능과 안전성을 균형 있게 제공한다.
  • 문자열 보간과 멀티라인 리터럴을 지원한다.
let name: String = "황민서"
let message = "안녕하세요, 제 이름은 \(name)입니다."

5) 불리언 (Bool)

  • 논리값 true/false를 표현한다.
  • 조건식에서만 사용되며 0/1과의 암묵 변환을 허용하지 않는다.
  • 의미가 드러나는 이름으로 가독성을 높인다.
let isLogin: Bool = true
if isLogin { print("로그인 성공") } else { print("로그인 필요") }

6) 배열 (Array)

  • 동일 타입 요소를 순서 있게 저장한다.
  • 값 타입이며 변경 시 복사-온-라이트로 최적화한다.
  • 인덱스는 0부터 시작한다.
let numbers: [Int] = [1, 2, 3]
var fruits = ["사과", "바나나"]
print(numbers[0])
fruits.append("딸기")

7) 딕셔너리 (Dictionary)

  • 키-값 쌍을 저장하는 컬렉션이다.
  • 키는 Hashable을 만족해야 한다.
  • 존재하지 않는 키 조회는 옵셔널을 반환한다.
var user: [String: Any] = ["name": "민서", "age": 23, "isStudent": true]
print(user["name"] as? String ?? "")

8) 세트 (Set)

  • 중복 없는 요소의 집합을 저장한다.
  • 요소는 Hashable을 만족해야 한다.
  • 합집합·교집합·차집합 같은 집합 연산을 제공한다.
var unique: Set<Int> = [1, 2, 2, 3]
print(unique) // {1, 2, 3}

9) 옵셔널 (Optional)

  • 값의 존재/부재를 Some/nil로 표현한다.
  • ? 표기로 선언하며 안전한 처리를 강제한다.
  • 옵셔널 바인딩, 체이닝, 패턴 매칭 등으로 해제한다.
var nick: String? = nil
nick = "minseo"
if let n = nick { print(n) } else { print("없음") }

 

let nickname: String? = "코딩학생"
if let nick = nickname {
    print("닉네임: \(nick)")
} else {
    print("닉네임이 없습니다.")
}

 

  • var nickname: String? = nil → 값이 없을 수도 있는 옵셔널 문자열을 선언하고 nil로 시작한다.
  • nickname = "코딩학생" → 옵셔널에 실제 문자열 값을 대입한다.
  • if let nick = nickname { ... } else { ... } → 옵셔널 바인딩으로 nickname이 nil이 아니면 안전하게 언래핑해 nick(비옵셔널)으로 사용한다. 이 코드에서는 nick이 "코딩학생"이므로 if 블록이 실행되어 print("닉네임: 코딩학생")을 출력한다.
  • 반대로 nickname이 nil이면 else 블록이 실행되어 "닉네임이 없습니다."를 출력한다.

초기화되지 않은 x를 print 에서 사용했기 때문에 생긴 오류
x를 Int 값 10으로 초기화했기 때문에 print(x) 에서 10이 정상 출력된다
양쪽 공백이 일관하지 않아 생긴 오류다
여러 인수를 콘솔에 출력하며, 값 사이 구분자는 기본 " " 이고 끝 문자는 기본 "\n" 으로 처리한다.

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

var age = 20
var name = "minseo"

print(age)                 // 변수 age 출력
print(age, name)           // 여러 값 출력 (공백으로 구분)
print("나이는 \(age)입니다") // 문자열 보간으로 값 출력

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

print("minseo")            // 문자열 출력
print("hwang")             // 문자열 출력

print("Hello", terminator: " ") // 줄 바꿈 대신 공백으로 끝내기
print("World!")                 // 같은 줄에 이어 출력

print("다음", terminator: "")    // 줄 바꿈/공백 없이 끝내기
print("입니다.")                // 바로 이어서 출력

print(12, separator: " ", terminator: "  ")

※ 주석 참고

위 코드를 xcode에서 실행한 화면
타입 추론으로 x는 Int로 결정되고, type(of:)가 Int를, MemoryLayout.size(ofValue:)가 64비트 환경의 Int 크기인 8바이트를 출력한다.
실수 리터럴 10.5로 인해 x는 Double 로 추론되고, type(of:)는 Double 을, MemoryLayout.size(ofValue:)는 64비트 환경의 Double 크기인 8바이트를 출력한다.

x를 Int 10으로 초기화하고 print(x)는 값 10을 출력한다.
print("x")는 문자 그대로 x를 출력한다.
print("\(x)")와 "값은 \(x)입니다."는 문자열 보간으로 10을 삽입해 출력한다.
Int32.min/max는 32비트 정수 범위(−2³¹ ~ 2³¹−1)를 출력한다.
Int.min/max는 플랫폼 정수 범위를 출력하며 64비트 환경에서는 −2⁶³ ~ 2⁶³−1이 된다.

"X"를 Character로 명시해 선언했기 때문에 type(of:)가 Character로 출력된다
let 으로 선언한 x는 상수라 재할당할 수 없는데 20을 대입하려 해서 생긴 오류, 값 변경이 필요하면 var x = 10 으로 선언한다.

 

왜 let이 var보다 권장되는가

1. 불변성 확보

let은 값이 한 번 정해지면 다시 바뀌지 않는다. 이는 코드의 안정성을 높이고, 상태 추적을 단순하게 만든다. 특히 멀티스레드 환경에서는 값이 변하지 않기 때문에 경쟁 조건(race condition)이나 데이터 불일치 위험을 줄일 수 있다.

2. 컴파일러 최적화 가능

컴파일러는 let으로 선언된 값을 더 강력하게 최적화할 수 있다. 예를 들어, 상수 폴딩(constant folding), 인라인 최적화, 불필요한 메모리 접근 제거 등이 가능하다. 반대로 var는 언제든 값이 변할 수 있으므로 최적화 여지가 줄어든다.

3. 의도 전달

코드에서 let을 사용하면 “이 값은 변경되지 않는다”라는 의도를 분명히 보여준다. 이는 코드 자체가 문서 역할을 하게 하며, 다른 개발자가 읽을 때 오해를 줄인다. API 설계에서도 let은 읽기 전용 데이터라는 신뢰를 준다.

4. 유지보수 용이성

값이 변할 수 있는 변수가 많을수록 디버깅과 유지보수가 어려워진다. 값이 어디서 어떻게 바뀌었는지 추적해야 하기 때문이다. let을 사용하면 변경 지점을 원천적으로 없애므로 코드 관리가 단순해진다.

5. 언어 철학

Swift는 안전성과 예측 가능성을 중시하는 언어다. 그래서 공식 문서에서도 “기본은 let, 꼭 필요할 때만 var”를 권장한다. 이는 Swift 코드의 일관성과 가독성을 높이는 원칙이다.

 

정리하면, let은 안전성, 최적화, 의도 명확화, 멀티스레드 안전성 측면에서 이점이 있다. 따라서 Swift에서는 기본적으로 let을 사용하고, 값 변경이 불가피한 경우에만 var를 사용하는 것이 바람직하다.

 

느낀 점

시뮬레이터를 먼저 돌려 보니 문법 학습의 방향이 분명했다.
Flappy Bird와 Playground 실습으로 타입·옵셔널·출력 동작의 감이 확실했다.
‘기본은 let’ 원칙과 스타일 가이드를 따르니 코드가 더 안정적이었다.