프로그래밍/Swift
Swift 기초 공부5
시르베어
2025. 2. 2. 22:46
익스텐션
- 구조체, 클래스, 열거형, 프로토콜 타입에 새로운 기능을 추가할 수 있음
- 추가할 수 있는 기능 (저장 프로퍼티는 불가능, 기존의 프로퍼티에 감시자 불가능)
- 연산 타입 프로퍼티 / 연산 인스턴스 프로퍼티
- 타입 메서드 / 인스턴스 메서드
- 이니셜라이저
- 서브스크립트
- 중첩 타입
- 특정 프로토콜을 준수할 수 있도록 기능 추가
- 기존에 존재하는 기능을 재정의할 수는 없음
- 상속 : 수직확장, 익스텐션 : 수평확장
extension 확장할타입이름: protocol1, protocol2 ... {
// 요구사항 구현
}
extension String { // 서브스크립트 확장
subscript(add: String){ return Self+add }
}
struct A {
var value: Int
init(_ value: Int){
self.value = value
}
}
extension A { // 이니셜라이저 확장
init(_ value: Double){
self.value = Int(value)
}
}
제네릭
- 어떤 타입에도 유연하게 대응할 수 있음
- 코드 중복을 줄일 수 있고 추상적인 표현도 가능
struct Stack<T> {
var arr: [T] = []
mutating func push(_ element: T){
self.arr.append(element)
}
mutating func pop() -> T? {
return self.arr.popLast()
}
...
}
extension Stack {
func isEmpty() -> Bool {
return self.arr.isEmpty
}
func top() -> T? {
return self.arr.last
}
}
타입 제약
func substract<T>(_ a: T, _ b: T) -> T { // "Binary operator '-' cannot be applied to two 'T' operands" 에러 발생
return a - b
}
func substract<T: BinaryInteger>(_ a: T, _ b: T) -> T {
return a - b
}
- 위의 코드에서 T가 BinaryInteger를 채택하면서 타입 제약을 해서 뺄셈을 진행할 수 있음
프로토콜 지향 프로그래밍
- 프로토콜을 정의할 때는 프로토콜의 요구사항을 구현할 수 없음 -> 익스텐션에는 프로콜이 요구하는 기능을 실제로 구현할 수 있음 (단, 저장 프로퍼티는 구현할 수 없음)
protocol A {
var data: Any { get }
func dataPrint()
}
extension A {
func dataPrint(){
print("data = \\(self.data)")
}
}
class a: A {
var data: Any = "test"
}
let value: a = a()
value.dataPrint() // "data = test"
ARC
- Auto Reference Counting (메모리 관리 기법)
- 클래스의 인스턴스에만 적용
- 참조 횟수가 0이 되는 순간 메모리에서 해제
강한참조
- 인스턴스가 계속해서 메모리에 남아있어야 하는 명분을 만들어 주는 것
- 인스턴스를 다른 인스턴스의 프로퍼티나 변수, 상수 등에 할당할 때 참조 횟수가 1 증가
- nil을 할당해주면 참조 횟수 1 감소
- 별도의 식별자를 명시하지 않으면 강한참조
강한참조 순환문제
- 인스턴스끼리 서로가 서로를 강한참조 할때 발생할 수 있음
- 메모리 누수 발생
- 이런 상황에서 디이니셜라이저는 작동하지 않음 (디이니셜라이저는 메모리에서 해제될때 호출 - 메모리가 누수되면 작동하지 않음)
class Number {
var partner: Number?
let number: Int
init(value: Int){
self.number = value
}
}
var A: Number? = Number(value: 10) // A 참조 1
var B: Number? = Number(value: 20) // B 참조 1
A?.partner = B // B 참조 2
B?.partner = A // A 참조 2
// 해당 소스에서 순환문제를 해결할려면 A?.partner = nil, B?.partner = nil을 처리해야함
A = nil // A 참조 1
B = nil // B 참조 1
약한참조
- 인스턴스의 참조 횟수를 증가 시키지 않음 (weak 키워드 사용)
- 옵셔널 변수만 약한 참조로 사용가능
class Number {
weak var partner: Number?
let number: Int
init(value: Int){
self.number = value
}
deinit {
print("소멸")
}
}
var A: Number? = Number(value: 10) // A 참조 1
var B: Number? = Number(value: 20) // B 참조 1
A?.partner = B // 참조가 증가하지 않음
B?.partner = A // 참조가 증가하지 않음
A = nil // A 참조 0
B = nil // B 참조 0
미소유참조
- 인스턴스의 참조 횟수를 증가 시키지 않음 (unowned)
- 자신이 참조하는 인스턴스가 메모리에서 해제되더라도 스스로 nil을 할당해주지않음 (즉, 메모리에서 해제한 뒤에 접근하면 런타임 에러가 발생한다) - 옵셔널 변수로 선언하지 않아도 됨