Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
Tags
- coordinator pattern
- viewDidAppear
- 플랫디자인
- 디자인 트렌드
- 픽셀
- 뉴북
- SWIFT
- 직장인자기계발
- 입력 개수 제한
- 8 그리드 시스템
- 패스트캠퍼스후기
- ios
- git
- 뉴모피즘
- 코드리팩토링
- viewDidLoad
- 머티리얼 디자인
- 직장인인강
- commit message
- 포인트
- commit
- Xcodebuild
- 스큐어모피즘
- commit messages
- 아이폰
- 패스트캠퍼스
- iOS앱개발올인원패키지Online.
- git workflow
- 패캠챌린지
- Git Tutorial
Archives
- Today
- Total
왕논의 연구실
swift의 소유권 개념 본문
반응형
1. 왜 ‘소유권 (ownership)’이 필요할까?
Swift 의 값 - 복사(copy) 기반 모델은 편리하지만,
- 고유-자원(파일 디스크립터, 락, GPU 버퍼 등)은 “한 번에 하나만” 소유되어야 안전합니다.
- 불필요한 ARC retain/release · 메모리 복사는 성능을 떨어뜨립니다.
이를 해결하기 위해 Swift 5.9~5.10에서 “값의 소유권 을 코드에 표현” 하는 세 가지 키워드가 도입되었습니다.
키워드 | 의미 | 대표 위치 |
---|---|---|
~Copyable (비복사/noncopyable) |
“이 값은 복사 불가, 이동-전용(move-only)” | 타입 선언 |
borrowing |
“잠깐 빌려쓰기”∙읽기 전용, 끝나면 호출자 소유권 유지 | 파라미터·메서드·클로저 |
consuming |
“소유권을 넘겨받아 소비”∙끝나면 호출자에서 더 못 씀 | 파라미터·메서드·클로저 |
2. ~Copyable
(Non-Copyable) — 값 자체가 “유일”해야 할 때
// 파일 디스크립터를 구조체 하나로 감싸고 싶다
struct FileDescriptor: ~Copyable {
private var rawFD: Int32
init(open path: String) throws {
rawFD = open(path, O_RDONLY)
}
func read(byteCount n: Int) -> [UInt8] { /* … */ }
deinit { close(rawFD) } // 고유 자원이므로 deinit 허용
}
struct
/enum
뒤에~Copyable
(틸드)만 붙이면 됩니다.- 복사 연산(대입, 인자 전달, 캡처 등)을 컴파일러가 금지 하므로, 실수로 두 곳에서 같은 파일을 닫는 버그가 사라집니다. (swift-evolution/proposals/0390-noncopyable-structs-and-enums.md at main · swiftlang/swift-evolution · GitHub)
‼️ 제약
- noncopyable 값은 아직 튜플·프로토콜 타입·제네릭 인수로 쓸 수 없습니다(향후 개선 예정). (swift-evolution/proposals/0390-noncopyable-structs-and-enums.md at main · swiftlang/swift-evolution · GitHub)
3. borrowing
— “읽기만, 복사 안 하고 빌려쓰기”
// fd를 잠깐 읽기만 한다 – 함수가 끝나면 caller가 그대로 소유
func printHeader(_ fd: borrowing FileDescriptor) {
let header = fd.read(byteCount: 128)
print(header)
} // 여기까지 fd는 여전히 유효
- 복사 금지 덕분에 “의도치 않은 ARC + 복사”가 사라지고,
- 읽기 전용이므로 함수 안에서
fd
를mutating
하거나deinit
을 호출할 수 없습니다. (swift-evolution/proposals/0377-parameter-ownership-modifiers.md at main · swiftlang/swift-evolution · GitHub)
4. consuming
— “소유권을 받아서 내가 파괴하거나 넘긴다”
// fd를 ‘소모’하여 파일 전체를 읽고, fd는 여기서 생이 끝난다
func slurpFile(_ fd: consuming FileDescriptor) -> [UInt8] {
var bytes: [UInt8] = []
while let chunk = try? fd.read(byteCount: 4096) {
bytes += chunk
}
// fd.deinit 자동 호출 → 파일 닫힘
return bytes
}
// 호출자 쪽
let fd = try FileDescriptor(open: "/tmp/foo")
let data = slurpFile(fd) // ✅ 이후 fd 사용 불가 → 컴파일 오류
- 파라미터가
consuming
이면 call-site 에서 값을 더 이상 쓸 수 없습니다. - 메서드에 붙이면
slurpFile
처럼self
소유권을 가져올 수도 있습니다. (swift-evolution/proposals/0377-parameter-ownership-modifiers.md at main · swiftlang/swift-evolution · GitHub)
5. borrowing
vs consuming
vs inout
목적 | 내부에서 수정? | 호출자 관점 | 복사 발생 |
---|---|---|---|
borrowing |
❌ | 그대로 유지 | ❌ (금지) |
consuming |
✅ 가능 | 더 이상 접근 불가 | ❌ (이동) |
inout |
✅ 가능 | 같은 변수에 반영 | ✅ 필요 시 복사 |
6. 값 복사가 꼭 필요할 땐 copy
/ consume
func duplicate(_ s: borrowing String) -> (String, String) {
(copy s, copy s) // 명시적 복사
}
let newFD = consume fd // 소유권 이동 후 fd는 무효
``` ([swift-evolution/proposals/0377-parameter-ownership-modifiers.md at main · swiftlang/swift-evolution · GitHub](https://github.com/apple/swift-evolution/blob/main/proposals/0377-parameter-ownership-modifiers.md))
---
### 7. 언제 써야 할까?
| 시나리오 | 권장 키워드 |
|----------|-------------|
| 파일·소켓·락·GPU 버퍼 등 **고유 자원** 캡슐화 | `~Copyable` |
| “읽기 전용으로 잠깐 사용” (로그 출력, 해시 계산) | `borrowing` |
| “리소스를 _닫거나_ 컨테이너에 옮겨 넣어야” 하는 API | `consuming` |
| 기존 값 수정 후 그대로 돌려주기 | `inout` 여전히 적합 |
---
### 8. 실무 팁
1. **라이브러리 공개 API**에는 `borrowing / consuming`을 미리 명시해서 ABI 안정성을 확보하세요. (바뀌면 바이너리 호환성 깨짐) ([swift-evolution/proposals/0377-parameter-ownership-modifiers.md at main · swiftlang/swift-evolution · GitHub](https://github.com/apple/swift-evolution/blob/main/proposals/0377-parameter-ownership-modifiers.md))
2. `Sendable` 프로토콜은 noncopyable 타입도 채택할 수 있어 **동시성 모델과 호환**됩니다. ([swift-evolution/proposals/0390-noncopyable-structs-and-enums.md at main · swiftlang/swift-evolution · GitHub](https://github.com/apple/swift-evolution/blob/main/proposals/0390-noncopyable-structs-and-enums.md))
3. Xcode 15.3 이상에서 _Build Setting → Experimental Features → Move-only Types_ 를 켜면 실험 기능을 바로 시험할 수 있습니다(Swift 5.10+ 기본 활성).
4. 컴파일 오류 메시지
* “`value used after consume`” ➜ `consuming` 후 재사용 시도
* “`copy of noncopyable value used`” ➜ noncopyable 값을 묵시적으로 복사
---
### 9. 한눈에 보는 예제 Playground
```swift
//: Move-only & ownership demo (Swift 5.10+)
struct Token: ~Copyable {
let id: UUID
deinit { print("Token deallocated:", id) }
}
func inspect(_ t: borrowing Token) { print("Inspect", t.id) }
func finish(_ t: consuming Token) {
print("Consume", t.id)
}
do {
let t = Token(id: .init())
inspect(t) // OK
finish(t) // t 소유권 이동
// inspect(t) // ❌ compile error – value consumed
}
// scope ends – Token already deallocated by finish()
요약
~Copyable
= “값 자체가 유일해야 하니 복사 금지”borrowing
= “잠깐 빌려서 읽기만”consuming
= “내가 받아서 처리하고 파괴(또는 이동)”
이 세 가지로 “값이 어디서 태어나고, 언제 파괴되는지”를 코드 수준에서 명확히 표현할 수 있어, 성능·안전성 둘 다 한층 끌어올릴 수 있습니다.
반응형
'iOS > Swift' 카테고리의 다른 글
iOS에서 UI 변경이 바로 적용되지 않는 이유 (0) | 2025.05.09 |
---|---|
ViewModel의 위치? View vs ViewController (0) | 2025.05.07 |
iOS 화면 구성 시 자주 사용하는 Override 함수 정리 (UIView / UIViewController) (0) | 2025.04.19 |
CoreBluetooth - 입문 (0) | 2025.04.17 |
Swift XCTest 정리 - 입문 (0) | 2025.04.15 |