iOS 프로그래밍 실무(4)

김제형·2025년 4월 10일

optional chaining

  • 옵셔널형의 프로퍼티나 메서드 호출 뒤에 "?" 사용
ex)
(pLocation?.coordinate.latitude)!

기본적인 옵셔널 언래핑 방법 실습

var x: String? = "Hi!"          
// x를 옵셔널 String 타입으로 선언하고 "Hi!"로 초기화. 옵셔널이므로 nil일 수도 있음.
print(x, x!)                    
// x와 x!를 출력. x는 옵셔널 값("Optional("Hi!")")으로, x!는 강제 언래핑하여 "Hi!"로 출력.
if let a = x {                  
// 옵셔널 바인딩: x가 nil이 아니면 a에 "Hi!"를 할당하고 블록 실행.
    print(a)                    
    // a는 언래핑된 "Hi!"이므로 "Hi!"를 출력.
}
let b = x!.count                
// x를 강제 언래핑(x!)하여 "Hi!"의 문자 개수를 계산. b는 Int 타입으로 3이 됨.
print(type(of:b), b)           
// b의 타입(Int)과 값(3)을 출력.
let b1 = x?.count               
// 안전한 옵셔널 체이닝: x가 nil이 아니면 count를 호출, b1은 Int? 타입으로 Optional(3)이 됨.
print(type(of:b1), b1, b1!)    
// b1의 타입(Int?), 값(Optional(3)), 강제 언래핑 값(3)을 출력.
let c = x ?? ""                 
// nil 병합 연산자: x가 nil이면 ""를 사용, 여기서는 x가 "Hi!"이므로 c는 "Hi!"가 됨.
print(c)                        
// c의 값 "Hi!"를 출력.

x의 값을 nil로 지정했을 때 경우

  • x에 값이 들어가지 않는 경우

옵셔널 체이닝의 강제언래핑과 바인딩의 차이

class Person {
    var name: String
    var age: Int
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}
let kim: Person = Person(name: "Kim", age: 20)
print(kim.age)
let han: Person? = Person(name: "Han", age: 25)

print((han?.age)!)
//옵셔널 체이닝 -> 강제언래핑

if let hanAge = han?.age {
    print(hanAge)
} else {
    print("nil")
}
//옵셔널 체이닝 -> 바인딩

옵셔널 바인딩과 강제 언래핑의 차이점

예외 처리 ( Error Handling )

  1. do-catch 구문
    가장 일반적이고 널리 사용되는 방법으로, 에러를 명시적으로 처리할 수 있음

  2. 옵셔널 값으로 에러 처리 (try?)
    에러를 간단히 무시하거나 실패 여부만 확인하고 싶을 때 사용

  3. 에러 전파 (Error Propagation)
    함수에 throws 키워드를 사용하여 발생한 에러를 호출한 코드로 전파
    호출한 코드에서 직접 에러를 처리하거나 다시 전파할 수 있음
    네트워크 호출이나 복잡한 로직에서 사용

  4. 단정 (try!)
    에러가 절대 발생하지 않을 것이라고 가정할 때 사용
    에러가 발생하면 프로그램이 크래시

가장 많이 사용하는 예외 처리 문

  • do~catch문으로 묶어준뒤 프로토콜 앞에 try를 붙여준다.
do{
    audioPlayer = try AVAudioPlayer(contentsOf : audioFile)
} catch let error as NSError{
    print("Errpr-initPlay : \(error)")
}

generic

  • 괄호의 종류별 용도와 예시

사용 방법

  • 용도가 완전히 같고 자료형만 다를 경우 모든 자료형을 선언하지 않고 축약적으로 만들 수 있는 방법이다.

  • 따로 지정된 것은 없지만 T로 암묵적 약속이 되어있다

일반 자료형에 generic 사용

func myPrint(a: Int, b: Int) {
print(b,a)
}
myPrint(a:1,b:2)
myPrint(a:2.5,b:3.5) //Error
//Int 형으로 선언되어있기 떄문이다
>
func myPrint<T>(a: T, b: T) {
print(b,a)
}
myPrint(a:1,b:2)
myPrint(a:2.5,b:3.5)
myPrint(a:"a" , b:"b")

클래스에서 generic 사용

class Box<T> {
    var item: T
    init(item: T) {
        self.item = item
    }
    func getItem() -> T {
        return item
    }
}
let intBox = Box(item: 12)
//Box<Int>(item: 123),generic class는 
//이렇게 쓰지만 타입 추론으로 <Int> 생략 가능
>
print(intBox.getItem()) // 12
let stringBox = Box(item: "Hello") // Box<String>(item: "Hello")
print(stringBox.getItem()) // Hello

Array

swift의 Array도 generic 구조체이다.

  • swift에서 빈배열을 만드는 3가지 방법
var x : [Int] = [] //빈 배열
var y = [Int\]() //*추천
var z : Array<Int\> = []
  • 빈배열에 값을 대입하는 세가지 방법
var a : [Int] = [1,2,3,4]
var b : Array<Int\> = [1,2,3,4]
var c : Array<Double\> = [1.2, 2.3, 3.5, 4.1]

@frozen struct Array<Element>
@frozen은 저장프로퍼티 추가, 삭제 불가

first, last 프로퍼티

  • array의 첫번째와 마지막 데이터를 가져올 수 있는 프로퍼티
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])
print(num.first!)
for i in 0...num.count-1{
    print(num[i])
}
print(num[1...2])
num[0...2] = [10,20,30]
print(num)

<결과>

array 추가/제거

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 num[0]=100
print(num)
print(x)

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

<결과>
[1, 2, 3, 10, 20]
Optional(1)
Optional(20)
1
20

Array 요소의 정렬

  • 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]
  • sorted는 원본의 값을 변경하지 않고 사용하는 잠시동안만 값이 변경 된다.
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

  • 모듈은 코드배포의 단일 유닛

접근수준의 단계

⬆️높은 접근 수준
open
public
package
internal
fileprivate
private
⬇️낮는 접근 수준

extension

  • 기존의 클래스, 구조체, 열거형, 또는 프로토콜 타입에 새로운 기능을 추가할 수 있는 강력한 문법이다

Extension의 특징

  1. 기존 타입에 새로운 기능을 추가할 수 있음.
  2. 저장 프로퍼티는 추가할 수 없으며, 연산 프로퍼티만 추가 가능.
  3. 기존 기능을 오버라이드할 수 없음.
  4. 초기화 구문, 메서드, 서브스크립트, 중첩 타입 등을 추가 가능.
  5. 특정 프로토콜을 준수하도록 만들 수 있음.
profile
개발자 지망생

0개의 댓글