Swift 시작하기 | iOS 개발 공식 언어 완벽 입문
이 글의 핵심
Swift 시작하기: iOS 개발 공식 언어 완벽 입문. Xcode 설치·Hello World.
시리즈 안내
#01 | 📋 전체 목차 | 다음: #02 변수와 타입
들어가며
Swift란?
Swift는 Apple 플랫폼과 서버·도구까지 쓰이는 안전성과 성능을 겨냥한 언어입니다. 값 타입·프로토콜(타입이 따라야 할 기능·규약을 묶어 둔 것) 중심 설계가 강조됩니다. 특징:
- ✅ 안전성: 타입 안전, 옵셔널(값이 없을 수 있음을 타입으로 표현)
- ✅ 빠름: C/C++ 수준 성능
- ✅ 간결함: 현대적 문법
- ✅ 상호운용: Objective-C 호환
- ✅ 오픈소스: Swift.org Swift vs Objective-C: | 특징 | Swift | Objective-C | |------|-------|-------------| | 문법 | 간결 | 복잡 | | 안전성 | 옵셔널 | Null 가능 | | 성능 | 빠름 | 빠름 | | 학습 곡선 | 완만 | 가파름 |
1. Xcode 설치
Mac에서 설치
- Mac App Store에서 Xcode 검색
- 다운로드 (약 12GB)
- 설치 완료 후 실행
Playground 사용
- Xcode 실행
- File > New > Playground
- 코드 작성 후 즉시 실행
2. Hello World
Playground에서
print("Hello, Swift!")
프로젝트에서
import Foundation
func main() {
print("Hello, Swift!")
}
main()
3. 변수와 상수
기본 사용
// 변수 (var)
var name = "홍길동"
name = "김철수" // OK
// 상수 (let)
let age = 25
// age = 26 // 컴파일 에러!
// 타입 명시
var score: Int = 100
let pi: Double = 3.14159
타입 추론
let message = "안녕하세요" // String
let count = 10 // Int
let price = 9.99 // Double
let isActive = true // Bool
4. 기본 타입
숫자 타입
// 정수
let a: Int = 10
let b: UInt = 20 // 양수만
// 실수
let x: Double = 3.14159 // 64비트
let y: Float = 3.14 // 32비트
// 연산
let sum = a + 5
let product = x * 2.0
문자열
// 변수 선언 및 초기화
let name = "홍길동"
let greeting = "안녕하세요, \(name)님!"
// 여러 줄
let multiline = """
첫 번째 줄
두 번째 줄
"""
// 문자열 연산
let fullName = "홍" + "길동"
let length = name.count
불리언
// 변수 선언 및 초기화
let isActive = true
let isCompleted = false
if isActive && !isCompleted {
print("진행 중")
}
5. 함수
기본 함수
func greet(name: String) {
print("안녕하세요, \(name)님!")
}
greet(name: "홍길동")
반환 값
func add(a: Int, b: Int) -> Int {
return a + b
}
let result = add(a: 10, b: 20)
print("결과: \(result)")
매개변수 레이블
Swift의 독특한 기능으로, 함수 호출 시 가독성을 높입니다:
// to, from: 외부 매개변수 레이블 (호출 시 사용)
// name, sender: 내부 매개변수 이름 (함수 본문에서 사용)
func greet(to name: String, from sender: String) {
// 함수 내부에서는 name, sender 사용
print("\(sender)가 \(name)에게 인사합니다.")
}
// 호출 시 외부 레이블 사용 (가독성 향상)
greet(to: "홍길동", from: "김철수")
// "to 홍길동, from 김철수" - 마치 자연어처럼 읽힘
// 레이블 없이 호출하려면 _ 사용
func add(_ a: Int, _ b: Int) -> Int {
return a + b
}
add(10, 20) // 레이블 없이 호출
매개변수 레이블의 장점:
- 함수 호출이 자연어처럼 읽힘
- 같은 타입의 매개변수를 명확히 구분
- API 설계 시 의도를 명확히 전달
6. 제어문
if-else
let age = 20
if age >= 18 {
print("성인")
} else {
print("미성년자")
}
for 루프
// 실행 예제
for i in 1...5 {
print(i)
}
let names = ["홍길동", "김철수", "이영희"]
for name in names {
print(name)
}
switch
let status = "active"
switch status {
case "active":
print("활성")
case "inactive":
print("비활성")
default:
print("알 수 없음")
}
7. 실전 예제
예제: 간단한 계산기
func calculate(operation: String, a: Double, b: Double) -> Double? {
switch operation {
case "+":
return a + b
case "-":
return a - b
case "*":
return a * b
case "/":
return b != 0 ? a / b : nil
default:
return nil
}
}
if let result = calculate(operation: "+", a: 10, b: 5) {
print("결과: \(result)")
}
if let result = calculate(operation: "/", a: 10, b: 0) {
print("결과: \(result)")
} else {
print("0으로 나눌 수 없습니다")
}
실전 심화 보강
실전 예제: Codable로 JSON 한 번에 디코딩하기
Xcode 없이도 Swift Package Manager로 콘솔에서 실험할 수 있습니다. Package.swift에 실행 타겟을 두고 아래를 실행해 보세요.
main.swift:
import Foundation
struct Repo: Codable {
let name: String
let stargazers_count: Int
}
let json = """
{"name":"swift","stargazers_count":68000}
""".data(using: .utf8)!
do {
let repo = try JSONDecoder().decode(Repo.self, from: json)
print("\(repo.name) ★ \(repo.stargazers_count)")
} catch {
print("디코딩 실패: \(error)")
}
자주 하는 실수
- 옵셔널을
!로 강제 언래핑해 런타임 크래시를 만드는 경우. if let/guard let범위를 벗어난 뒤 옵셔널을 사용하려는 경우.- 구조체를 값 타입으로 두고 참조 공유가 필요한데 클래스로 안 바꾸는 경우(또는 그 반대).
주의사항
- Swift 버전·플랫폼에 따라 사용 가능한 API가 다릅니다(
#available).
실무에서는 이렇게
- 팀에서 SwiftFormat/SwiftLint 규칙을 공유합니다.
- 작은 모듈부터 SPM 패키지로 쪼개 재사용성을 높입니다.
비교 및 대안
| 언어 | 메모 |
|---|---|
| Swift | 안전성·플랫폼 통합 |
| Kotlin | Android·멀티플랫폼 |
| Dart | Flutter UI |
추가 리소스
심화: 메모리 안전성과 소유권 모델
입문 예제만으로는 “Swift가 안전하다”는 말이 추상적으로 느껴질 수 있습니다. 여기서는 컴파일 타임·런타임이 무엇을 보장하려 하는지, 그리고 Rust의 소유권과 어떻게 다른지를 짧게 짚습니다.
메모리 안전(Memory safety)이 가리키는 것
메모리 안전은 “유효하지 않은 주소를 읽거나 쓰지 않는다”는 넓은 목표를 두고, Swift는 그중에서도 특히 다음을 강하게 겨냅니다.
- 미초기화 읽기 금지:
let·var는 사용 전에 반드시 초기화되어야 하며, 분석 가능한 경로에서 이를 어기면 컴파일 에러가 납니다. - nil 접근 방지: 옵셔널이 아닌 타입은
nil이 될 수 없고, 옵셔널은 언래핑·체이닝으로만 안전하게 풀도록 유도합니다. 이는 널 포인터 역참조를 상당 부분 형(type) 수준에서 제거합니다. - 배타적 접근(Exclusivity): 같은 변수에 대해 겹치는 구간에서 동시에 가변 접근하지 못하도록 규칙이 있습니다. 이는 데이터 레이스로 이어지는 미정의 동작을 줄이기 위한 층입니다. 클로저가
inout을 캡처하는 패턴 등에서 컴파일러가 거부하는 이유가 여기에 있습니다.
C/C++에서 익숙한 “초기화되지 않은 스택 값 읽기”, “해제된 메모리 접근(use-after-free)” 같은 범주의 버그를 가능한 한 설계 단계에서 배제하려는 방향이라고 이해하면 됩니다.
소유권(ownership)이라는 말을 Swift에서 쓸 때
소유권이라는 용어는 Swift 5.9 이후 이동 전용(move-only) 타입 논의와 함께 더 자주 등장합니다. 다만 Swift의 기본 모델은 Rust의 소유권·수명·대여(borrow checker)와 동일하지 않습니다.
- 참조 타입(
class): 인스턴스는 힙에 있고, 강한 참조의 개수를 ARC(Automatic Reference Counting)로 추적합니다. “소유”는 참조가 몇 개나 강하게 잡고 있는가에 가깝고, 순환 참조는weak/unowned로 끊는 것이 일반적입니다. - 값 타입(
struct,enum): 복사 의미론을 따릅니다. 다만Array·String처럼 내부에 버퍼를 두는 타입은 Copy-on-Write로 실제 복사를 지연합니다. “값 타입이므로 항상 스택에만 있다”는 설명은 부정확할 수 있습니다. - inout, mutating: 메서드나 함수가 값을 제자리에서 바꿀 권한을 요청할 때 쓰이며, 이때도 배타적 접근 규칙과 맞물립니다.
정리하면, Swift에서 말하는 소유권은 “ARC 아래의 참조 수명”과 “값 타입의 복사·배타적 접근”이 합쳐진 실무 규칙에 가깝고, Rust 수준의 정적 대여 검사를 기대하면 모델이 다릅니다.
실무에서 기억할 한 줄
안전한 언어라도 동시성(concurrency)과 C 브리징·원시 포인터가 섞이면 보장이 달라집니다. 메모리 안전은 기본 언어 서브셋에서 강하고, 그 경계를 넘을수록 명시적 계약과 도구(스레드 샌itizer, Instruments)가 필요합니다.
정리
핵심 요약
- Swift: iOS/macOS 공식 언어
- Xcode: 통합 개발 환경
- Playground: 빠른 실험 도구
- 안전성: 타입 안전, 옵셔널
- 성능: C/C++ 수준
다음 단계
다른 언어와 비교
관련 글
- SwiftUI 기초 | View, State, Binding
- C++ 초보자가 자주 하는 실수 Top 15 | 컴파일 에러부터 런타임 크래시까지
- C++ 크로스 플랫폼 기초 완벽 가이드 | 플랫폼 감지·std::filesystem
- HTML/CSS 시작하기 | 웹 개발 첫걸음
- Java 시작하기 | JDK 설치부터 Hello World까지
심화 부록: 구현·운영 관점
이 부록은 앞선 본문에서 다룬 주제(「Swift 시작하기 | iOS 개발 공식 언어 완벽 입문」)를 구현·런타임·운영 관점에서 다시 압축합니다. 도메인별 세부 구현은 글마다 다르지만, 입력 검증 → 핵심 연산 → 부작용(I/O·네트워크·동시성) → 관측의 흐름으로 장애를 나누면 원인 추적이 빨라집니다.
내부 동작과 핵심 메커니즘
flowchart TD A[입력·요청·이벤트] --> B[파싱·검증·디코딩] B --> C[핵심 연산·상태 전이] C --> D[부작용: I/O·네트워크·동시성] D --> E[결과·관측·저장]
sequenceDiagram participant C as 클라이언트/호출자 participant B as 경계(런타임·게이트웨이·프로세스) participant D as 의존성(API·DB·큐·파일) C->>B: 요청/이벤트 B->>D: 조회·쓰기·RPC D-->>B: 지연·부분 실패·재시도 가능 B-->>C: 응답 또는 오류(코드·상관 ID)
- 불변 조건(Invariant): 버퍼 경계, 프로토콜 상태, 트랜잭션 격리, FD 상한 등 단계별로 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
- 결정성: 순수 층과 시간·네트워크·스케줄에 의존하는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
- 경계 비용: 직렬화, 인코딩, syscall 횟수, 락 경합, 할당·GC, 캐시 미스를 의심 목록에 둡니다.
- 백프레셔: 생산자가 소비자보다 빠를 때 버퍼·큐·스트림에서 속도를 줄이는 신호를 어디에 둘지 정의합니다.
프로덕션 운영 패턴
| 영역 | 운영 관점 질문 |
|---|---|
| 관측성 | 요청 단위 상관 ID, 에러율·지연 p95/p99, 의존성 타임아웃·재시도가 대시보드에 보이는가 |
| 안전성 | 입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가 |
| 신뢰성 | 재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가 |
| 성능 | 캐시·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가 |
| 배포 | 롤백 룬북, 카나리/블루그린, 마이그레이션·피처 플래그가 문서화되어 있는가 |
| 용량 | 피크 트래픽·디스크·FD·스레드 풀 상한을 주기적으로 검증하는가 |
스테이징은 데이터 양·네트워크 RTT·동시성을 프로덕션에 가깝게 맞출수록 재현율이 올라갑니다.
확장 예시: 엔드투엔드 미니 시나리오
앞선 본문 주제(「Swift 시작하기 | iOS 개발 공식 언어 완벽 입문」)를 배포·운영 흐름에 맞춰 옮긴 체크리스트입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.
- 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드를 경계에 둔다.
- 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 로그·메트릭·트레이스에서 한 흐름으로 본다.
- 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
- 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지 확인한다.
- 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값을 점검한다.
handle(request):
ctx = newCorrelationId()
validated = validateSchema(request)
authorize(validated, ctx)
result = domainCore(validated)
persistOrEmit(result, idempotentKey)
recordMetrics(ctx, latency, outcome)
return result
문제 해결(Troubleshooting)
| 증상 | 가능 원인 | 조치 |
|---|---|---|
| 간헐적 실패 | 레이스, 타임아웃, 외부 의존성, DNS | 최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검 |
| 성능 저하 | N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스 | 프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거 |
| 메모리 증가 | 캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납 | 상한·TTL·힙/FD 스냅샷 비교 |
| 빌드·배포만 실패 | 환경 변수, 권한, 플랫폼 차이, lockfile | CI 로그와 로컬 diff, 런타임·이미지 버전 핀 |
| 설정 불일치 | 프로필·시크릿·기본값, 리전 | 스키마 검증된 설정 단일 소스와 배포 매트릭스 표준화 |
| 데이터 불일치 | 비멱등 재시도, 부분 쓰기, 캐시 무효화 누락 | 멱등 키·아웃박스·트랜잭션 경계 재검토 |
권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.
배포 전에는 git add → git commit → git push 후 npm run deploy 순서를 권장합니다.
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. Swift 시작하기: iOS 개발 공식 언어 완벽 입문. Xcode 설치·Hello World로 흐름을 잡고 원리·코드·실무 적용을 한글로 정리합니다. Swift·스위프트·iOS 중심으로 설명합니다. Start no… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
- Swift 변수와 타입 | var, let, 옵셔널
- [2026] Swift 컬렉션 내부 | Array·Dictionary·Set과 Copy-on-Write
- Kotlin 시작하기 | Android 공식 언어 완벽 입문
- SwiftUI 입문 | 선언적 UI, 상태, MVVM
이 글에서 다루는 키워드 (관련 검색어)
Swift, 스위프트, iOS, 입문 등으로 검색하시면 이 글이 도움이 됩니다.