Swift는 Apple의 생태계(iOS, macOS, watchOS, tvOS 등)를 위한 강력하고 직관적인 프로그래밍 언어입니다. Swift는 안전성, 속도, 모던한 문법을 강조하며 개발자가 효율적으로 코드를 작성할 수 있도록 돕습니다. 아래에서는 Swift의 주요 특징과 중요한 문법 요소들을 예제와 함께 자세히 설명합니다.
---
## 1. Swift의 특징
- **안전성**: Swift는 변수의 사용 전 초기화, 옵셔널 타입, 메모리 관리를 통해 런타임 에러를 최소화합니다.
- **모던한 문법**: 간결하고 직관적인 문법 덕분에 가독성이 높고, 코드 유지보수가 용이합니다.
- **고성능**: 컴파일러 최적화를 통해 높은 성능을 제공하며, Objective-C와의 호환성도 지원합니다.
- **함수형 프로그래밍 지원**: 클로저, 고차함수(map, filter, reduce 등)를 활용하여 선언적 프로그래밍이 가능합니다.
---
## 2. 변수와 상수
Swift에서는 `var`를 사용해 변수(값이 변경될 수 있음)를, `let`을 사용해 상수(값이 변경되지 않음)를 선언합니다.
```swift
// 변수 선언
var greeting = "Hello"
greeting = "Hi"
// 상수 선언
let pi = 3.14159
// pi = 3.14 // 컴파일 에러 발생: 상수는 변경할 수 없습니다.
```
---
## 3. 데이터 타입과 타입 추론
Swift는 정적 타입 언어이지만, 타입 추론 기능이 있어 선언 시 타입을 명시하지 않아도 초기값을 기반으로 타입을 결정합니다.
```swift
var integerNumber = 42 // Int 타입
var doubleNumber = 3.14 // Double 타입
var isSwiftFun = true // Bool 타입
var greetingMessage = "Hello" // String 타입
```
또한, 명시적으로 타입을 지정할 수도 있습니다.
```swift
var explicitInteger: Int = 100
var explicitDouble: Double = 99.99
```
---
## 4. 제어문
### 조건문 (if, switch)
Swift의 조건문은 C 계열 언어와 유사하지만, 조건문에 반드시 불리언(Boolean) 값이 와야 합니다.
```swift
let score = 85
if score >= 90 {
print("A 학점")
} else if score >= 80 {
print("B 학점")
} else {
print("C 학점 이하")
}
```
`switch` 문은 각 케이스가 반드시 완전성을 갖추어야 하며, `default` 케이스를 통해 모든 경우를 처리할 수 있습니다.
```swift
let fruit = "Apple"
switch fruit {
case "Apple":
print("사과입니다.")
case "Banana":
print("바나나입니다.")
default:
print("알 수 없는 과일입니다.")
}
```
### 반복문 (for-in, while)
`for-in` 반복문은 시퀀스(sequence)를 순회할 때 주로 사용합니다.
```swift
for number in 1...5 {
print(number)
}
```
`while` 문은 조건이 참일 때 반복 실행합니다.
```swift
var count = 0
while count < 5 {
print("현재 count: \(count)")
count += 1
}
```
---
## 5. 함수
Swift에서 함수는 `func` 키워드를 사용하여 정의합니다. 함수는 매개변수와 반환값을 가질 수 있습니다.
```swift
func greet(name: String) -> String {
return "안녕하세요, \(name)님!"
}
let message = greet(name: "Swift")
print(message)
```
매개변수에 기본 값을 지정할 수도 있습니다.
```swift
func multiply(_ a: Int, by b: Int = 2) -> Int {
return a * b
}
print(multiply(3)) // 3 * 2 = 6
print(multiply(3, by: 4)) // 3 * 4 = 12
```
---
## 6. 클로저 (Closures)
클로저는 코드 블록을 캡슐화한 것으로, 변수에 할당하거나 함수의 인자로 전달할 수 있습니다. 대표적인 예로 고차함수인 `map`, `filter`, `reduce`가 있습니다.
```swift
let numbers = [1, 2, 3, 4, 5]
// 클로저를 사용하여 각 숫자에 2를 곱함
let doubled = numbers.map { (number: Int) -> Int in
return number * 2
}
print(doubled) // [2, 4, 6, 8, 10]
// 더 간결하게 표현 가능
let doubledConcise = numbers.map { $0 * 2 }
print(doubledConcise)
```
---
## 7. 클래스와 구조체
Swift에서는 객체 지향 프로그래밍을 위해 `class`와 `struct`를 제공합니다. 클래스는 상속이 가능하지만, 구조체는 값 타입으로 복사됩니다.
### 클래스 예제
```swift
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
func introduce() -> String {
return "안녕하세요, 제 이름은 \(name)이고, \(age)살입니다."
}
}
let person = Person(name: "Alice", age: 30)
print(person.introduce())
```
### 구조체 예제
```swift
struct Point {
var x: Int
var y: Int
func display() -> String {
return "(\(x), \(y))"
}
}
var point1 = Point(x: 10, y: 20)
var point2 = point1 // 값 복사
point2.x = 30
print(point1.display()) // (10, 20)
print(point2.display()) // (30, 20)
```
---
## 8. 옵셔널 (Optionals)
옵셔널은 값이 없을 수 있음을 나타내며, 변수에 `nil` 값을 허용합니다. 옵셔널 값을 안전하게 다루기 위해 `if let` 구문이나 `guard let` 구문을 사용합니다.
```swift
var optionalString: String? = "Hello, Swift!"
print(optionalString) // Optional("Hello, Swift!")
// 옵셔널 바인딩을 통한 안전한 값 추출
if let unwrappedString = optionalString {
print("언래핑된 값: \(unwrappedString)")
} else {
print("값이 없습니다.")
}
// 옵셔널 강제 언래핑 (값이 nil이 아니라고 확신할 때)
print(optionalString!) // 주의: nil일 경우 런타임 에러 발생
```
---
## 9. 프로토콜 (Protocols)
프로토콜은 특정 기능을 수행하기 위한 메서드, 속성, 기타 요구사항을 정의합니다. 클래스, 구조체, 열거형 등은 이 프로토콜을 채택하여 구현할 수 있습니다.
```swift
protocol Drivable {
func drive()
}
class Car: Drivable {
func drive() {
print("자동차가 달립니다.")
}
}
let myCar = Car()
myCar.drive()
```
---
## 10. 에러 처리
Swift에서는 `Error` 프로토콜을 준수하는 타입을 정의하고, `throw`, `try`, `catch` 구문을 통해 에러를 처리할 수 있습니다.
```swift
enum FileError: Error {
case fileNotFound
case unreadable
}
func readFile(filename: String) throws -> String {
if filename != "existingFile.txt" {
throw FileError.fileNotFound
}
return "파일 내용"
}
do {
let content = try readFile(filename: "nonexistent.txt")
print(content)
} catch FileError.fileNotFound {
print("파일을 찾을 수 없습니다.")
} catch {
print("알 수 없는 에러가 발생했습니다.")
}
```
---
## 11. 제네릭 (Generics)
제네릭을 사용하면 타입에 상관없이 재사용 가능한 코드를 작성할 수 있습니다. 예를 들어, 배열의 요소를 교환하는 함수를 작성해보겠습니다.
```swift
func swapValues<T>(_ a: inout T, _ b: inout T) {
let temp = a
a = b
b = temp
}
var first = 10
var second = 20
swapValues(&first, &second)
print("first: \(first), second: \(second)") // first: 20, second: 10
```
---
## 결론
Swift는 모던하고 안전한 프로그래밍 언어로, 직관적인 문법과 다양한 기능을 통해 개발자가 효율적으로 앱을 개발할 수 있도록 돕습니다.