var x: String? ="Hi"// x는 옵셔널 문자열로 선언되고, "Hi"로 초기화됨. Hi를 지우면 x는 nil이 됨.// x와 x! 출력: x는 옵셔널 값 그대로, x!는 강제로 언래핑된 값을 출력print(x, x!) // "Hi"일 때: Optional("Hi") "Hi" 출력// nil일 때: nil -> x!에서 런타임 에러 (강제 언래핑 실패)// if let 구문을 사용해 x가 nil이 아닌 경우에만 a에 값을 바인딩iflet a = x {
print(a) // x가 "Hi"일 때: "Hi" 출력 (a는 String 타입)// x가 nil일 때: 이 블록은 실행되지 않음
}
// x!로 강제 언래핑 후 문자열 길이를 계산let b = x!.count // x가 "Hi"일 때: b는 2 (Int 타입, "Hi"의 길이)// x가 nil일 때: 런타임 에러 (nil을 강제 언래핑)print(type(of: b), b) // "Hi"일 때: Int 2 출력// x?.count로 옵셔널 체이닝 사용, x가 nil이면 nil 반환let b1 = x?.count // x가 "Hi"일 때: b1은 Optional(2) (Int? 타입)// x가 nil일 때: b1은 nilprint(type(of: b1), b1, b1!) // "Hi"일 때: Optional<Int> Optional(2) 2 출력// nil일 때: Optional<Int> nil -> b1!에서 런타임 에러// nil 병합 연산자(??)로 x가 nil이면 기본값 "" 사용let c = x ??""// x가 "Hi"일 때: c는 "Hi" (String 타입)// x가 nil일 때: c는 "" (빈 문자열)print(c) // "Hi"일 때: "Hi" 출력// nil일 때: "" 출력
Swift에서 ? 와 ! 의 차이 (선언 및 실행문 예시 포함)
var x: Int? vs var x: Int! 비교 표
한눈에 보는 차이 요약
// Person 클래스 정의classPerson{
var name: String// 이름 속성var age: Int// 나이 속성// 생성자 (Initializer)init(name: String, age: Int) {
self.name = name // 인스턴스 name에 매개변수 name 할당self.age = age // 인스턴스 age에 매개변수 age 할당
}
}
// Person 클래스의 인스턴스 kim 생성 (옵셔널 아님)let kim: Person=Person(name: "Kim", age: 20)
// 옵셔널이 아니므로 바로 속성 접근 가능print(kim.age) // 출력: 20// 옵셔널 타입의 Person 인스턴스 han 선언let han: Person? =Person(name: "Han", age: 25)
// print(han.age) // ❌ 오류 발생: han은 옵셔널이므로 바로 접근 불가// print(han!.age) // ✅ 가능하지만 위험: 강제 언래핑 (nil일 경우 crash 발생)// 옵셔널 체이닝으로 접근: 안전하게 age 값을 가져옴print(han?.age) // 출력: Optional(25) — 값이 있을 경우 Optional 타입으로 출력됨// 옵셔널 체이닝 후 강제 언래핑: 값이 있을 때만 가능print((han?.age)!) // 출력: 25 — 괄호 덕분에 안전하게 강제 언래핑// 옵셔널 바인딩으로 안전하게 값 추출iflet hanAge = han?.age {
print(hanAge) // 출력: 25
} else {
print("nil") // han이 nil일 경우 출력될 메시지
}
// 제네릭(Generic) Box 클래스 정의classBox<T> {
var item: T// 어떤 타입이든 저장 가능init(item: T) {
self.item = item // 초기화
}
funcgetItem() -> T {
return item // 저장된 item 반환
}
}
// Int 타입의 제네릭 Box 생성 (타입 명시적)let intBox =Box<Int>(item: 123)
// 또는 타입 추론 가능 (Swift가 <Int> 생략 허용)let anotherIntBox =Box(item: 456)
// 제네릭으로 만든 Box이므로 다양한 타입 사용 가능let stringBox =Box(item: "Hello") // Box<String>(item: "Hello") 와 동일print(intBox.getItem()) // 출력: 123print(stringBox.getItem()) // 출력: Hello
Swift의 주요 제네릭 구조체(Generic Struct) 목록
구조체
이름설명
Array<Element>
여러 요소를 순서대로 저장하는 리스트 (예: [Int], [String])
Dictionary<Key, Value>
키-값 쌍으로 데이터를 저장 (예: [String: Int])
Set<Element>
중복 없는 컬렉션 (예: Set<String>)
Optional<Wrapped>
값이 있거나 없을 수 있는 타입 (Int?, String?)
Result<Success, Failure>
성공/실패를 표현하는 값 (에러 처리 시 사용)
Range<Bound>
범위를 나타냄 (예: 0..<10)
ClosedRange<Bound>
닫힌 범위 (0...10)
UnsafePointer<Pointee>
포인터 타입 (C 연동 시 사용)
Slice<Base>
배열의 부분 범위 표현
StrideThrough<Strideable>
간격을 두고 순회하는 범위
IndexSet
인덱스 집합 (내부적으로 제네릭 타입을 활용함)
ArraySlice<Element>
배열의 잘라낸 부분 (부분 배열)
여러 프로그래밍 언어에서의 Collection Type 비교표
언어
Array /List
Set
Dictionary / Map
Tuple
Swift
Array<Int> 또는 [Int]
Set<String>
[String: Int]
("Tom", 30)
Python
[1, 2, 3] (list)
{1, 2, 3}
{"a": 1, "b": 2}
("Tom", 30)
Java
ArrayList<Integer>
HashSet<String>
HashMap<String, Integer>
없음 (대신 class 사용)
JavaScript
[1, 2, 3] (Array)
new Set([1, 2, 3])
{"a": 1, "b": 2} (Object), new Map()
없음 (배열로 대체)
C++
vector<int>
set<int>
map<string, int>
tuple<string, int>
C#
List<int>
HashSet<string>
Dictionary<string, int>
Tuple<string, int>
Kotlin
listOf(1, 2, 3)
setOf("a", "b")
mapOf("a" to 1)
Pair("Tom", 30)
Go
[3]int (고정 배열), []int (슬라이스)
map[T]struct{} (유사 Set)
map[string]int
여러 변수로 분해
Rust
Vec<i32>
HashSet<String>
HashMap<String, i32>
(String, i32)
var number : [Int] = []
var odd = [Int]()
var even : Array<Int> =Array()
print(number)
number.append(100)
print(number[0])
number.append(200)
print(number[0], number[1],number)
// 기본 배열 선언: 숫자 0을 5개 직접 나열var x = [0, 0, 0, 0, 0]
print(x) // 출력: [0, 0, 0, 0, 0]// 배열 생성 함수 사용: 0을 6번 반복하여 배열 생성var x1 =Array(repeating: 0, count: 6)
print(x1) // 출력: [0, 0, 0, 0, 0, 0]// 명시적으로 Int 타입을 지정한 배열 생성: 1을 3개 반복var x2 = [Int](repeating: 1, count: 3)
print(x2) // 출력: [1, 1, 1]// String 타입의 배열 생성: "A"를 4개 반복var x3 = [String](repeating: "A", count: 4)
print(x3) // 출력: ["A", "A", "A", "A"]
P는 프로퍼티를 M은 메소드를 뜻합니다.
데이터에서 첫번째 데이터와 마지막 데이터를 가져오는 방법.
let num = [1, 2, 3, 4]
let num1 = [Int]()
print(num.first, num.last)//Optional(1) Optional(4)print(num1.first, num1.last)//nil niliflet f = num.first, let l = num.last {
print(f,l) //1 4
}
가장 낮은 제한 수준으로, 클래스와 클래스 멤버에만 적용 가능. 다른 모듈에서도 상속 및 재정의가 가능.
클래스 및 클래스 멤버
Public
동일 모듈 및 다른 모듈에서 접근 가능하지만, 상속 및 재정의는 불가능.
클래스, 구조체, 열거형, 함수, 변수 등
Package
동일 패키지 내에서만 접근 가능. Swift Package Manager(SPM)을 사용할 때 패키지 간의 접근을 제어하는 데 유용.
모든 엔티티
Internal
동일 모듈 내에서만 접근 가능. 기본 접근 수준으로, 별도로 명시하지 않으면 Internal로 설정됨.
모든 엔티티
Fileprivate
동일 파일 내에서만 접근 가능. 파일 단위로 구현 세부사항을 숨길 때 사용.
모든 엔티티
Private
정의된 범위(클래스, 구조체 등) 내에서만 접근 가능. 가장 높은 제한 수준으로, 특정 코드 블록 외부로 노출되지 않음.
모든 엔티티
extensionDouble{
var squared : Double {
returnself*self
}
}
let myValue: Double=3.5print(myValue.squared) //과제 12.25print(3.5.squared) //Double형 값에도 .으로 바로 사용 가능 12.25print(myValue.isZero) //instance property, 결과? false