[ABI Stability]
ABI란 Application Binary Interface, 응용 프로그램과 라이브러리 사이에 필요한 저수준 인터페이스에 대한 정의이다.
기계코드에 대한 통신 규칙을 정의하며, 프레임워크 또는 라이브러리들의 구성요소는 이 binary language를 사용하여 서로 통신한다.
프로그램을 나타내는 세부사항을 Run time에 기입하며, Run time에 컴파일된 코드가 상호작용할 수 있다.
Keynote
1. ABI Stability를 지원함으로써 버전 호환이 된다. (Migration 과정이 개선될 것이다.)
2. 개발자는 Swift로 작성된 closed source 3rd-party libraries를 만들고, 이를 미리 컴파일된 framework로 배포할 수 있다. 이는 현재 (ABI 안정화 이전), Objective-C에만 가능했었다. framework 제작자는 소스파일 대신, 미리 컴파일된(Pre-compiled) 바이너리를 제공할 수 있으므로, 외부 dependencies를 프로젝트에 통합(integrate)해야 하는 경우, 빌드시간이 훨씬 빨라질 수 있다.
3. 번들 size가 줄어든다. frameworks 폴더에 swift 표준 라이브러리를 더이상 포함할 필요가 없기 때문에, 앱의 크기고 줄어든다.
ABI의 기능
1. CPU명령어 (registers, stack organiztion, memory access type)
2. calling convention (함수 호출, arguments 전달, 값 리턴)
3. OS에 대한 시스템호출
4.Data layout
5. Type metadata
6. mangling
7. runtime
8. standard library
ABI Stability 두 가지 목표
1. Source compatibility (소스 호환성)
최신 컴파일러가 이전 버전의 Swift로 작성된 코드를 컴파일 할 수 있는 것을 의미하며 새로운 Swift 버전이 나왔을 때, Migration 해야 하는 번거로움을 줄이는 데 그 목적이 있다.
이 Source compatibility가 없으면 내 모든 소스들과 패키지를 동일한 버전의 Swift로 작성해야 하는 버전 잠금(version-lock)에 직면하게 된다. 근데 Source compatibility가 있다면 여러 Swift 버전에서 단일 코드 기반을 유지하면서 새로운 버전의 Swift를 사용할 수 있다.
2. Binary framework & runtime compatibility
Binary framework & runtime compatibility를 통해서 여러 Swift 버전에서 작동하는 binary form의 framework를 배포할 수 있다.
예를 들어 앱에 third party framework를 추가하고 이 third party framework가 Swift 4.0으로 작성되어 있다고 가정하면 사용 버전을 Swift 4.2로 업데잍트 했을 때, Error가 발생할 여지가 생긴다.
하지만 Binary framework & runtime compatibility가 있으면 문제가 발생하지 않는다.
Binary framework에는 framework API의 소스레벨 정보를 전달하는 Swift Module 파일과 Run time에 로드 되는, 컴파일된 구현을 제공하는 공유 라이브러리가 모두 포함된다.
즉, `Binary framework = Swift Module 파일 + 공유 라이브러리` 이다.
Binary framework의 두 가지 목표가 있다.
첫 번째, Module format stability(모듈 형식 안정성)은 framework의 공용 인터페이스에 대한 컴파일러의 표현인 모듈 파일을 안정화시킨다.
두 번째, ABI stability는 다른 Swift 버전으로 컴파일된 앱과 라이브러리 간 Binary compatibility를 가능하게 한다.
Swift 5.0 이전 버전의 Swift는 ABI Stability을 지원하는 언어가 아니기 때문에, 모든 바이너리는 자체적인 Swift Dynamic Library 버전을 번들로 제공한다.
f.e) Swift 3.0 APP1 / Swift 3.2 APP2
APP1: Swift 3.0 Dynamic Library (3.0 ABI 포함) Bundle
APP2; Swift 3.2 Dynamic Library (3.2 ABI 포함) Bundle
Swift는 iOS에 종속되어 있는 것이 아니기 때문에, 앱 내에 각각 존재한다.
왜냐하면 Swift가 ABI stability를 지원하고 있지 않기 때문에, 다른 버전의 OS에서 실행되려면 모든 바이너리(APP)이 Swift Dynamic Library를 제공해야만 하기 때문이다.
약 5MB 크기로, 그렇게 많은 부분을 차지하고 있진 않다. (IPA를 열면 Swift standard libraries (.dylib)를 찾을 수 있음)
만약 Swift가 ABI stability를 지원하게 된다면, Swift Dynamic Library가 각 앱마다 번들 되는 것이 아니라, (i/Mac 등) OS의 일부로 종속되게 된다. 즉, ABI는 모든 Swift 버전과 호환된다.
APP1이 Swift 5.0을 사용하고, APP2가 Swift 5.2를 사용하더라도 각 앱마다 Swift가 번들 되는 것이 아니라, OS에 포함된 Swift ABI를 사용하므로 dylib를 앱에 패키징할 필요가 없어진다.
[Module Stability]
Keynote
Module Stability는 라이브러리의 진화를 지원한다. 클라이언트를 다시 컴파일 할 필요없이 라이브러리의 `새 버전`을 제공할 수 있다.
Compile Time 에서는?
ABI stability는 runtime에 Swift 버전을 mixing하는 것이다. 그럼 compile time에서는?
현재 Swift는 수동으로 작성된 헤더파일이 아니라 `MagicKit`이라는 framework와 같은 라이브러리 인터페이스를 표현하기 위해 SwiftModule이라는 불투명한(opaque) 아카이브 포맷을 사용한다.
SwiftModule 포맷 역시 현재 컴파일러 버전과 맞물려 있어, 다른 버전의 Swift로 `MagicKit`을 구축하면, 개발자는 MagicKit을 import 할 수 없게 된다.
즉, 앱 개발자와 라이브러리 작성자는 같은 버전의 컴파일러를 사용해야 한다는 의미인 것이다.
이러한 제한을 제거하기 위해, 라이브러리 작성자는 module statbility라 불리는 기능을 구현해야 한다.
현재는 라이브러리가 변경되면, 해당 라이브러리를 사용하는 모든 앱을 다시 컴파일 해야 한다.
이것의 장점은 컴파일러가 앱에서 사용하는 라이브러리의 정확한 버전을 알고 있기 때문에, 코드 크기를 줄이고, 앱을 더 빨리 실행할 수 있는 추가 가정을 할 수 있다는 것이다.
그러나 그런 가정은 다음 버전에서는 사실이 아닐 수 있다.
[Property Wrapper]
[Set / Dictionary]
새로 생성된 Set / Dictionary 인스턴스마다 다른 hash seed를 사용한다.
결과적으로 동등한 Set / Dictionary의 요소 순서는 이전 버전보다 훨씬 더 자주 다르게 된다.
[Hash]
Cocoa Object의 일관성 없는 해싱을 방지하기 위해, NSObject의 hashValue 프로퍼티는 더이상 override 할 수 없다.
hashValue의 override는 Swift 4.2에서 deprecated가 되었다.
hashing과 equality는 함께 움직여야 한다. (hash를 override했으면 isEqual도 override, 반대도 마찬가지)
[Flatten nested optionals resulting from 'try?']
Swift의 try? 구문의 중첩된(nested) Optional이 만들어질 여지가 많다.
중첩된 Optional은 사용자가 추론하기 어려우며 따라서 피하려고 노력한다.
위와 같이 (특히 pattern matiching) 중첩된 Optional은 정신 건강에 해롭다.
Swift 5.0 이상부터는 try?는 Optional Chaining을 미러링한다.
결과 값이 Optional이 아니면 Optilnal로 감싸진다.
결과 값이 Optional이면 추가적인 Optional이 설정되지 않는다.
[Handling Future Enum Cases]
추후 enum의 case가 추가될 것을 고려하여 @unknown 키워드가 추가
[Enhancing String Literals Delimiters to Support Raw Text]
String 안에 " 와 같이 특수 문자를 사용하는 경우 # 키워드를 통해 개선
// Before
let nTom = "N_TOM : \"안녕하세요.\""
// Now
let nTom = #"N_TOM : "안녕하세요.""#
print(#""본인"소개: \#(N_TOM)"#) // "본인"소개: "안녕하세요."
[Introduce compactMap Values to Dictionary]
dictionary 버전의 compactMap
[count(where:)]
[Character Properties]
Character의 유용성과 프로그래밍 접근성을 높이기 위해 몇 가지 쿼리 추가 (isWhitespace, isNewline ...)
[Support 'less than' operator in compilation conditions]
if swift(>= 4.2) 방식의 '>=' 연산자만 허용 했었는데, '<' 연산자도 허용
[Adding isMultiple to BinaryInteger]
isEven, isOdd, isMultiple를 BinaryInteger Protocol에 추가 (horizontal space를 절약하기 위함...)
[Add Result to the Standard Library]
위 코드는 Alamofire의 Result.swift 인데, 이와 흡사한 Result 타입이 Swift Library에 추가되었다.
[Synthesize default values for the member wise initializer]
현재 class defulat initializer를 제공하는 것 처럼, 프로퍼티가 옵셔널 혹은 default 값을 가지고 있을 경우 이를 제외한 initialzier를 제공한다.
[Static and class subscript]
static subscript, class subscript 허용
[Implicit returns from single-expression functions]
computed property의 경우 대부분 single-expression인데, 이 경우 return 생략 가능
[Matching optional enums against non-optional values]
[Opaque Result Types]
`some` 키워드를 통해 function에 정확한 return type을 지정하는 대신, 준수하는 protocol을 선언하여 concrete return type을 숨길 수 있다.
참고
https://zeddios.tistory.com/650
https://zeddios.tistory.com/680?category=685736
https://zeddios.tistory.com/771
https://github.com/apple/swift-evolution/blob/master/proposals/0230-flatten-optional-try.md
https://nshipster.com/propertywrapper/#auditing-property-access
'Swift' 카테고리의 다른 글
[Swift] Understanding Swift Performance - Class와 Protocol (0) | 2020.03.09 |
---|---|
[Swift 5.1] Property Wrapper 개념과 사용 예시, 그리고 한계점. (1) | 2020.02.29 |