컴파일 에러가 나는데 왜 나는지 모른다
let name = "개발자리" // String 추론
let age: Int = 10 // 명시적 타입
var score = 0 // 변경 가능
score += 10
// name = "다른이름" // ❌ 컴파일 에러!
print("이름: \(name)")
print("점수: \(score)")
let으로 선언한 변수를 나중에 바꾸려고 하면 어떤 에러가 나는가?let x = 42에서 Swift가 타입을 Int로 추론하는 원리는 무엇인가?var nickname: String? = nil
// if let 언래핑
if let name = nickname {
print("닉네임: \(name)")
} else {
print("닉네임 없음")
}
// ?? nil 병합
let display = nickname ?? "익명"
print("표시: \(display)")
// 옵셔널 체이닝
let count = nickname?.count
print("글자수: \(count)")
String과 String?은 완전히 다른 타입인가? 둘의 관계는?if let과 guard let은 언래핑한 값을 사용할 수 있는 범위(scope)가 어떻게 다른가?! 강제 언래핑이 crash를 일으키는 정확한 조건은 무엇인가?user?.profile?.name에서 중간에 nil이 하나라도 있으면 결과는?// Array
var fruits = ["사과", "바나나", "포도"]
fruits.append("딸기")
print(fruits[0])
print(fruits.count)
// Dictionary
let scores: [String: Int] = [
"수학": 90,
"영어": 85,
]
print(scores["수학"] ?? 0)
// Set
let tags: Set = ["Swift", "iOS", "Swift"]
print(tags.count) // 중복 제거
array[5]에서 배열 크기가 3이면 어떤 에러가 발생하는가?Dictionary에서 없는 키로 접근하면 crash가 나는가, nil이 나는가?Set의 contains()가 Array의 contains()보다 빠른 이유는 무엇인가?let numbers = [1, 2, 3, 4, 5]
// map — 변환
let doubled = numbers.map { $0 * 2 }
print(doubled)
// filter — 걸러내기
let evens = numbers.filter { $0 % 2 == 0 }
print(evens)
// compactMap — nil 제거
let strings = ["1", "a", "3"]
let nums = strings.compactMap { Int($0) }
print(nums)
// reduce — 합산
let sum = numbers.reduce(0, +)
print(sum)
map과 forEach의 차이는 무엇인가? 둘 다 각 요소를 순회하는데 왜 구분하는가?compactMap은 map과 어떻게 다른가? 언제 써야 하는가?reduce(0, +)에서 0과 +는 각각 무엇인가?let names = ["Charlie", "Alice", "Bob"]
// 1. 기본 형태
let a = names.sorted(by: {
(a: String, b: String) -> Bool in
return a < b
})
// 2. 타입 추론
let b = names.sorted(by: { a, b in a < b })
// 3. 단축 인자명
let c = names.sorted(by: { $0 < $1 })
// 4. 후행 클로저
let d = names.sorted { $0 < $1 }
print(d)
{ (a: String, b: String) -> Bool in return a < b }를 가장 짧게 줄이면 어떻게 되는가?$0, $1은 무엇을 의미하는가? $2까지 있다면 파라미터가 몇 개인가?Button { } 문법이 가능한 이유는?class DataLoader {
var data: String?
func load() {
// ✅ [weak self] 필요
URLSession.shared.dataTask(
with: url
) { [weak self] data, _, _ in
guard let self else { return }
self.data = String(
data: data!, encoding: .utf8
)
}.resume()
}
}
// ❌ SwiftUI View에서는 불필요
struct MyView: View {
var body: some View {
Button("탭") {
// struct이므로 순환참조 없음
print("no [weak self] needed")
}
}
}
[weak self]를 붙이면 self가 어떤 상태가 될 수 있는가?[weak self]가 필요 없는 이유는 무엇인가?// ❌ 타입 불일치
let num: Int = 42
// let text: String = num
// ✅ 해결
let text: String = String(num)
// ❌ 옵셔널 미언래핑
let name: String? = "Kim"
// print("Hello " + name)
// ✅ 해결
if let name {
print("Hello " + name)
}
String?를 String이 필요한 곳에 넣으면 어떤 에러가 나는가? 해결 방법 3가지는?enum FileError: Error {
case notFound
case permissionDenied
}
// 에러를 던질 수 있는 함수
func readFile(name: String) throws -> String {
guard name != "" else {
throw FileError.notFound
}
return "파일 내용"
}
// do-catch로 에러 처리
do {
let content = try readFile(name: "")
print(content)
} catch FileError.notFound {
print("❌ 파일을 찾을 수 없습니다")
} catch {
print("❌ 알 수 없는 에러: \(error)")
}
// try? — 에러 시 nil 반환
let content = try? readFile(name: "")
// Result 타입
func safeRead(name: String) -> Result<String, FileError> {
do {
return .success(try readFile(name: name))
} catch let e as FileError {
return .failure(e)
} catch {
return .failure(.notFound)
}
}
throws가 붙은 함수를 try 없이 호출하면 어떻게 되는가?try?와 try!의 차이는 무엇인가? try!는 언제 써도 되는가?Result<Success, Failure>를 쓰는 것과 throws를 쓰는 것은 어떻게 다른가?try?로 처리하면 무엇을 잃는가?var name: String? = "김개발"
var age: Int? = nil
var tags: [String]? = ["Swift", "iOS"]
// if let
if let name {
print("이름: \(name)") // 이름: 김개발
}
// guard let
func printAge() {
guard let age else {
print("나이 정보 없음") // 출력됨
return
}
print("나이: \(age)")
}
printAge()
// ?? nil 병합
let displayAge = age ?? 0
print("나이: \(displayAge)") // 나이: 0
// 옵셔널 체이닝
let count = tags?.count
print("태그 수: \(count)") // Optional(2)
let first = tags?.first?.uppercased()
print("첫 태그: \(first)") // Optional("SWIFT")
struct Student {
let name: String
let score: Int
}
let students = [
Student(name: "Alice", score: 92),
Student(name: "Bob", score: 75),
Student(name: "Charlie", score: 88),
Student(name: "Diana", score: 64),
Student(name: "Eve", score: 95),
]
// map — 이름만 추출
let names = students.map { $0.name }
print(names)
// ["Alice", "Bob", "Charlie", "Diana", "Eve"]
// filter — 80점 이상
let topStudents = students.filter { $0.score >= 80 }
print(topStudents.map { $0.name })
// ["Alice", "Charlie", "Eve"]
// reduce — 평균 점수
let total = students.reduce(0) { $0 + $1.score }
let average = Double(total) / Double(students.count)
print("평균: \(average)") // 평균: 82.8
let numbers = [5, 2, 8, 1, 9, 3]
// === sorted ===
// 1) 기본
numbers.sorted(by: { (a: Int, b: Int) -> Bool in
return a < b
})
// 2) 타입 추론
numbers.sorted(by: { a, b in a < b })
// 3) 단축 인자명
numbers.sorted(by: { $0 < $1 })
// 4) 후행 클로저
numbers.sorted { $0 < $1 }
// === filter ===
// 1) 기본
numbers.filter({ (n: Int) -> Bool in
return n > 3
})
// 2) 타입 추론
numbers.filter({ n in n > 3 })
// 3) 단축 인자명
numbers.filter({ $0 > 3 })
// 4) 후행 클로저
numbers.filter { $0 > 3 }
// === map ===
// 1) 기본
numbers.map({ (n: Int) -> String in
return "\(n)점"
})
// 2) 타입 추론
numbers.map({ n in "\(n)점" })
// 3) 단축 인자명
numbers.map({ "\($0)점" })
// 4) 후행 클로저
numbers.map { "\($0)점" }