안녕하세요.
이번에는 inlinable, usableFromInline 속성(attribute)에 대해 알아볼게요.
# 1. inlinable
inlinable에 대한 설명에 앞서, Client <-> Framework 간 동작 방식에 대해서 설명할게요.
이해를 돕기 위해 MyFramework라는 framework 안에 Person이란 클래스를 만들어봤어요.
사용하는 곳(Client)에서는 아래처럼 쓰겠죠?
내부적으로는 런타임 때 아래처럼 동작해요.
1. (Client) MyFramework에서 Person이 가지고 있는 method 들 중에서 어떤 게 sayHello() method야?
2. (MyFramework) Person의 2번째 method 임. 호출해줄게.
3. (Client) ㅇㅋ. ㄱㅅ..
4. (Client) 그럼 isGenerationZ() method는 어떤거야?
5. (MyFramework) 3번째 임. 호출해줄게..
6. (Client) ㅇㅋ.. ㄱㅅㄱㅅ...
Client <-> Framework 간 상호작용을 하다 보니 간단한 method 일지라도 오버헤드가 생깁니다.
이런 경우, 성능을 향상시키기 위해서 inlinable 속성을 사용합니다. 이렇게요!!
inlinable 속성을 사용하면, inlinable로 선언된 구현부가 모듈 인터페이스에 포함됩니다.
그래서 client 쪽에서 framework API를 호출하는 부분이 API의 구현부로 치환되기 때문에 오버헤드를 줄일 수 있습니다.
(대충 요런 느낌이랄까요??ㅎㅎ)
swiftinterface 파일을 보면 구현부가 추가되어 있는 것을 볼 수 있어요.
나머지 method도 inlinable 속성을 넣어줘 볼까요?
에러가 발생합니다. 사실 당연해요. birthYear는 private 인스턴스 변수이기 때문에 일반적인 방법으로는 inline으로 처리할 수가 없는 것이죠.
이럴 때, usableFromInline 속성을 사용합니다.
# 2. usableFromInline
usableFromInline 속성을 사용하면 인스턴스 변수, method, computed property, subscript, initializer, deinit 등을 inline에서 사용할 수 있게 됩니다.
다만, usableFromInline 속성을 사용하려면 internal level로 선언되어야 해요.
이렇게요.
swiftinterface 파일에도 구현부가 잘 추가된 것을 볼 수 있습니다.
근데 한 가지 이상한 점 있지 않나요?
inlinable 속성을 추가한 구현부에서 인스턴스 변수를 사용하려면 인스턴스 변수에 usableFromInline 속성을 줘야 하고 그 인스턴스 변수는 internal level 이어야 합니다.
인스턴스 변수가 internal level 이기 때문에, 모듈 바깥에서는 인스턴스 변수가 노출되지만 read/write를 할 수 없겠죠?
근데 또 inlinable로 인해 모듈 바깥에서 호출하는 부분이 구현부로 치환되고, 구현부 안에서는 인스턴스 변수를 read/write 할 수 있기 때문에..
결국은 모듈 바깥에서 인스턴스 변수를 read/write 할 수 있게 되는 거 아닌가??
답은 당연히... NO 입니다ㅎ.....
모듈 바깥에서 internal로 선언된 인스턴스 변수에 직접 접근하는 경우 컴파일 타임 에러를 주고,
inline 부분은 런타임 때 모듈과 상호동작을 하기 때문에 문제가 없다고 해요.
# 3. 추가 정보
inlinable 속성은 public 또는 internal로 선언된 곳에서만 사용할 수 있습니다. (private, fileprivate에서는 사용할 수 없습니다.)
usableFromInline 속성은 internal로 선언된 곳에서만 사용할 수 있죠.
또한 inlinable 속성이 추가된 구현부에서 정의한 함수나 클로저의 경우 암묵적(implicitly)으로 inlinable로 정의된다고 해요.
inlinable로 선언한 이후에는, 최적화 등을 위해서 구현부를 수정하는 것은 괜찮지만 return 값을 바꾸는 행위는 지양 한다고 합니다..
client 쪽에서는 re-compile을 하지 않는 이상 이전의 return 값을 사용하게 되고 이 경우, client와 framework 간 특정 상황 & 특정 input에 의해서만 return 값이 달라지는 버그가 생길 수 있다고 해요.
(근데... client 쪽에서 모듈 업데이트를 하면 바뀐 return 값이 적용되는 거 아닌가요...? 이 부분은 잘 이해가 안 되네요..ㅠㅠㅠ 혹시 알고 계신 분 있으시면 알려주세요ㅠㅠ)
## 참고
- https://developer.apple.com/videos/play/wwdc2019/416/
- https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID587
- https://docs.swift.org/swift-book/ReferenceManual/Attributes.html#ID597
이번 글은 여기서 마무리.
'Swift' 카테고리의 다른 글
@autoclosure (2) | 2022.12.15 |
---|---|
Optional에서의 map, flatMap (0) | 2022.09.04 |
[Swift 5.7] if let shorthand (0) | 2022.07.05 |
inout (0) | 2022.06.05 |
Modeling errors (0) | 2022.05.27 |