[WWDC15] Building Better Apps with Value Types in Swift
Referenc sementics
Unintended Sharing
- 같은 주소를 참조해 원하지 않는 값의 변화가 발생할 수 있다.
Manual Copy
- copy() 메소드로 값만 복사할 수 있다.
- heap 영역에 할당해 cost가 크고 copy()를 실수로 하지 못하면 위험이 크다.
Defensive Copying
Immutability
- 함수형 프로그래밍 언어는 immutability을 가진 reference semantic을 합니다.
- mutation을 가진 reference semantic발생하는 문제들을 제거합니다.
- 주의할 단점
- 어색한 인터페이스로 이어질 수 있습니다.
- 불변 이라는 특성이 변화하는 실제 상황들과 잘 맞지 않을 수 있습니다.
Awkward Immutable Interfaces
- 새로운 Temperature을 생성해서 주입하는 과정이 비효율적이다(heap에 새로 할당해야함)
- 진짜 불변성을 지키기 위해서는 home.oven.temperature에 새로운 값을 넣어주는게 아니라 home도 새로운 temperature와 함께 새로 만들어 줘야한다.
Value Semantics
Variables Are Logically Distinct
- 값 타입은 공유가 생기지 않는다.
- Swift의 fundamental type들은 value type이다.
- Swift의 collection들은 value type이다.
- value type을 담고있는 tuple, struct, enum 들은 value type입니다.
Mutation When You Want it
Freedom from Race Conditions
- 다른 스레드에서 접근해도 값을 복사해가서 경쟁 상태 발생하지 않는다.
Copies Are Cheap
- 값 타입 복사의 비용이 크지않다.
- 확장이 가능한 자료구조들은
copy-on-write
를 사용합니다.
- 값이 변경되기 전에는 복사된 값을 참조하고 있다가 변경이 발생했을 때 진짜 복사를 진행한다.
Mixing Value Types and Reference Types
Immutable References and Equatable
- 값 타입 안에서의 참조는 공유를 하지 않습니다.
- image2의 image를 변경해도 image의 image는 변하지 않는다.
- 값 타입 안에 참조 타입이 있을때 Equatable을 채택해 ==를 구현하려면 ===를 사용해 같은 주소를 참조하는지 확인할 수 도있지만 변화가 발생했을 때 같은 주소를 참조하지 않아 적절하지 않습니다.
- isEqual 메소드를 사용해서 객체를 비교해야합니다.
Reference to Mutable Objects
- addLineToPoint에 의해 참조 타입의 프로퍼티에 변화가 생겨 문제가될 수 있다.
- func 앞에 mutating 키워드가 없지만 path는 참조 타입이기 때문에 컴파일러는 에러를 표시하지 않습니다.
- 우리는 path에 쓰기전에 copy를 진행해야합니다.
- path 인스턴스를 private로 만듭니다.
- pathForReading: 연산 프로퍼티를 사용해 private인 path를 read합니다.
- pathForWriting: 연산 프로퍼티를 사용해 path에 write를 할때는 mutating 키워드를 명시하고 copy()한 path를 반환합니다.
- pathForReading 사용해 isEmty 수정
- pathForWriting 사용해 addLineToPoint수정, pathForWriting에 mutating이 명시됐으므로 addLineToPoint 메소드에도 mutating을 명시해줘야한다.
- 복사전에는 같은 UIBezierPath를 참조합니다.
- addLineToPoint메소드를 사용하면 복사가 일어나 다른 UIBezierPath를 참조하게 됩니다.
How to use in practice
- for문의 loop에서 매번 copy가 발생해 성능에 좋지않다.
- UIBezierPath()를 새로만들고 BezierPath 인스턴스를 새로 만들어 반환해줍니다.
- 이렇게 하면 1번의 copy만 발생합니다.
Uniquely Referenced Swift Objects
- isUniquelyReferencedNonObjc 메소드를 사용하면 필요한 상황에만 copy()를 사용하게 최적화할 수 있습니다.
참고