카테고리 없음

iOS프로그래밍실무 (04.10)

k0223 2025. 4. 10. 16:50

옵셔널을 언래핑하는 여러가지 방법

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에 값을 바인딩
if let 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은 nil
print(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 클래스 정의
class Person {
    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 — 괄호 덕분에 안전하게 강제 언래핑

// 옵셔널 바인딩으로 안전하게 값 추출
if let hanAge = han?.age {
    print(hanAge)  // 출력: 25
} else {
    print("nil")   // han이 nil일 경우 출력될 메시지
}

 

주요 프로그래밍 언어별 예외 처리 문법 비교표

 

 

 

Swift 예외 처리 방법 (사용 빈도순)

 

 
 Swift 스로윙 함수 10가지 예시

 

 

 

https://developer.apple.com/documentation/avfaudio/avaudioplayer

 

프로그래밍에서 괄호의 용도 정리

괄호 이름 주요 용도 예시설명
() 소괄호 1. 함수 호출
2. 함수 선언 매개변수
3. 연산 우선순위 지정
print("Hello")
(a + b) * c
연산자보다 먼저 계산되도록 지정하거나 함수 호출 시 사용
{} 중괄호 1. 코드 블록 정의
2. 조건문/반복문 본문
3. 클래스/함수 본문
if x > 0 { print(x) }
func hello() { }
실행할 코드 블록을 감쌈
[] 대괄호 1. 배열/리스트
2. 인덱싱
3. 딕셔너리 키 접근
let arr = [1, 2, 3]
arr[0]
배열, 리스트, 딕셔너리 등에 접근할 때 사용
<> 꺾쇠 괄호 1. 제네릭(Generic) 타입 정의
2. HTML/XML 태그 (언어에 따라 다름)
Array<Int>
<div></div>
Swift나 Java에서 제네릭 타입 지정 또는 HTML에서 태그로 사용

 

// 제네릭(Generic) Box 클래스 정의
class Box<T> {
    var item: T                           // 어떤 타입이든 저장 가능
    
    init(item: T) {
        self.item = item                 // 초기화
    }
    
    func getItem() -> 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())      // 출력: 123
print(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 nil
if let f = num.first, let l = num.last {
	print(f,l) //1 4
 }

 

 

첨자(subscript)로 항목 접근

var num = [1, 2, 3, 4]

print(num[0], num[3])       
// 출력: 1 4

print(num.first!)           
// 출력: 1

for i in 0...num.count-1 {
    print(num[i])
}
// 출력:
// 1
// 2
// 3
// 4

print(num[1...2])
// 출력: [2, 3]  // 슬라이스 (인덱스 1부터 2까지)

num[0...2] = [10, 20, 30]    
// 인덱스 0~2 (1,2,3) → 10, 20, 30으로 대체됨

print(num)
// 출력: [10, 20, 30, 4]

 

Array : 추가 / 제거

//let x = [1, 2, 3, 4] //불변 배열은 초깃값에서 변경 불가
//x.append(5)
var num = [1,2,3]
print(num)
num.append(4)
print(num)
num.append(contentsOf: [6, 7, 8])
print(num) //[1, 2, 3, 4, 6, 7, 8]
num.insert(5, at:4)
print(num) //[1, 2, 3, 4, 5, 6, 7, 8]
num.remove(at:3)
print(num) //[1, 2, 3, 5, 6, 7, 8]
num.removeLast()
print(num) //[1, 2, 3, 5, 6, 7]
print(num.firstIndex(of:2)) //Optional(1), 2가 처음으로 나오는 첨자
if let i = num.firstIndex(of:2) { //2가 처음으로 저장된 방의 값을 20으로 바꿈
    num[i] = 20 //num[1] = 20
}
print(num) //[1, 20, 3, 5, 6, 7]
num=num+num
print(num) //[1, 20, 3, 5, 6, 7, 1, 20, 3, 5, 6, 7]
num+=[8,9]
print(num) //[1, 20, 3, 5, 6, 7, 1, 20, 3, 5, 6, 7, 8, 9]
num.removeAll()
print(num) //[]

 

Array는 구조체이므로 값 타입

var num = [1,2,3]
var x = num //x는 num의 복사본, 별개의 배열
print(x) //[1, 2, 3]
num[0]=100
print(num) //[100, 2, 3]
print(x) //[1, 2, 3]

 

Array 요소의 최댓값 최솟값 :max(), min()

var num = [1,2,3,10,20]
print(num) //[1, 2, 3, 10, 20]
print(num.min()) //Optional(1)
print(num.max()) //Optional(20)
print(num.min()!) //1
print(num.max()!) //20

 

Array 요소의 정렬

var num = [1,5,3,2,4]
num.sort() //오름차순 정렬하여 원본 변경
print(num) //[1, 2, 3, 4, 5]
num[0...4] = [2,3,4,5,1]
num.sort(by:>) //내림차순 정렬하여 원본 변경
print(num) //[5, 4, 3, 2, 1]
num[0...4] = [2,3,4,5,1]
num.reverse() //반대로 정렬하여 원본 변경
print(num) //[1, 5, 4, 3, 2]
print(num.sorted()) //오름차순 정렬 결과를 리턴하고, 원본은 그대로, var x = num.sorted()
//[1, 2, 3, 4, 5]
print(num) //[1, 5, 4, 3, 2]
print(num.sorted(by:>)) //내림차순 정렬 결과를 리턴하고, 원본은 그대로
//[5, 4, 3, 2, 1]
print(num)//[1, 5, 4, 3, 2]

 

여러 프로그래밍 언어의 Access Control 비교표

접근 제어자 Swift Java C++ Python C# 설명
public public public public (기본: public) public 어디서든 접근 가능
internal internal (기본) 없음 없음 없음 없음 같은 모듈 내에서만 접근 가능 (Swift 고유)
protected 없음 protected protected 없음 protected 서브클래스 및 같은 패키지/모듈에서 접근 가능
fileprivate fileprivate 없음 없음 없음 없음 같은 파일 내에서만 접근 가능 (Swift 고유)
private private private private _변수명 (관례) private 같은 클래스/객체 내에서만 접근 가능
package-private 없음 (접근 제어자 없음) 없음 없음 없음 Java에서 같은 패키지 내 접근 (default)
module / internal internal 없음 없음 없음 internal 모듈 단위 접근 허용 (Swift/C# 지원)

Swift의 Access Control

Access 
Level
설명 적용 범위
Open 가장 낮은 제한 수준으로, 클래스와 클래스 멤버에만 적용 가능. 다른 모듈에서도 상속 및 재정의가 가능. 클래스 및 클래스 멤버
Public 동일 모듈 및 다른 모듈에서 접근 가능하지만, 상속 및 재정의는 불가능. 클래스, 구조체, 열거형, 함수, 변수 등
Package 동일 패키지 내에서만 접근 가능. Swift Package Manager(SPM)을 사용할 때 패키지 간의 접근을 제어하는 데 유용. 모든 엔티티
Internal 동일 모듈 내에서만 접근 가능. 기본 접근 수준으로, 별도로 명시하지 않으면 Internal로 설정됨. 모든 엔티티
Fileprivate 동일 파일 내에서만 접근 가능. 파일 단위로 구현 세부사항을 숨길 때 사용. 모든 엔티티
Private 정의된 범위(클래스, 구조체 등) 내에서만 접근 가능. 가장 높은 제한 수준으로, 특정 코드 블록 외부로 노출되지 않음. 모든 엔티티

 

extension Double {
    var squared : Double {
        return self * self
    }
}
let myValue: Double = 3.5
print(myValue.squared) //과제 12.25
print(3.5.squared) //Double형 값에도 .으로 바로 사용 가능 12.25
print(myValue.isZero) //instance property, 결과? false