티스토리 뷰

Swift

Swift 5.0 변경사항

Zedd0202 2019. 2. 17. 18:55
반응형


안녕하세요 :) Zedd입니다. 

벌써 Xcode 10.2 베타가 나왔는데요, 다운만 12시간...받은듯..

지금은 집컴이라 저번에 Snapshot으로 다운받은 걸 써볼거에요.

Swift 5.0에서는 문법적인 변화...보단 ABI 안정성이 반가운 소식이에요. (개인적으로)


올해는 조바심을 안내려고 했는데 자꾸 몸이 안따라주고 그러니까 조바심이 많이 나네요.

실천은 안하면서 조바심만 내는게 얼마나 어이가 없는지.

가장 큰 적은 자기 자신이라는 말이 뼈저리게 느껴집니다....

하루가 한 40시간 정도 되면 얼마나 좋을까요..



Swift 5.0



Swift의 ABI를 안정화 시키는 것이야말로..Apple의 오랜 목표였다고 할 수 있어요!!

Swiift의 ABI가 안정화 되면 “언어의 완성”을 위한 중요한 이정표이지만 

Swift의 에코시스템에서의 궁극적인 이점은 앱과 라이브러리간 

binary compatibility를 가능하게 하는 것이에요. 

binary compatibility가 제공되면 머다?? 

앞으로(Swift 5.0이상) Swift 컴파일러로 빌드된 앱은 다른 버전으로 빌드된 라이브러리랑 통신(?)할 수 있다는 것이죠. 




ABI 안정성이 확정되면서, 가장 큰 변화로 App Thinning을 안살펴볼 수 없겠죠. :)

 iOS 12.2, watchOS 5.2 및 tvOS 12.2이상으로 배포되는 앱은 

더이상 앱 번들 내에 Swift 표준 라이브러리 및 “overlay” 라이브러리를 내장 할 필요가 없어집니다.

(overlay는 뭔지 모르겠네요 “overlay”라 적혀있음)






Swift는 ABI stability을 지원하는 언어가 아닙니다.

그래서 모든 바이너리(App이라고 생각하시면 됩니다.)는 자체적인 Swift Dynamic Library 버전을 번들로 제공합니다.

예를들어 App1이 Swift 3.0을 사용하고 있다면, Swift 3.0 Dynamic Library (3.0 ABI 포함)를 번들로 묶습니다.

App2가 Swift 3.2를 사용하고 있다면, 역시나 Swift 3.2 Dynamic Library (3.2 ABI 포함)를 번들로 묶습니다.

중요한 사실은 Swift는 iOS 운영체제에 살고있지(?) 않으며 앱내에 각각!!! 존재한다는 것입니다.

왜냐하면 Swift가 ABI stability를 지원하고 있지 않기 때문에, 다른 버전의 OS에서 실행되려면 모든 바이너리(앱)이 Swift Dynamic Library를 제공해야만 하는 것이죠.

약 5MB의 크기로, 그렇게 많은 부분을 차지하고 있진 않습니다. (IPA를 열면 swift standard libraries (.dylib)를 찾을 수 있을거에요)



만약 Swift가 ABI stability를 지원하게 된다면, 

Swift Dynamic Library가 각 앱마다 번들되는게 아니라, (i/mac 등) OS의 일부로 들어가게 됩니다. 

(Swift런타임과 Swift표준 라이브러리는 Objective-C런타임과 마찬가지로 OS에 실릴 것 입니다. )

즉!!!! ABI는 모든 Swift 버전과 호환됩니다. 

App1이 Swift 5.0을 사용하고, App2가 Swift 5.2를 사용한다고 해도, 

각 앱마다 Swift가 번들되는것이 아니라 OS에 포함 된 Swift ABI를 사용하게됩니다.

즉, dylib를 앱에 패키징 할 필요가 없어집니다!!! 

따라서, 우리는 OS에서 제공되는 혜택을 누릴 수가 있는 것이죠.



출처: https://zeddios.tistory.com/654 [ZeddiOS]



제가 예전에 ABI 안정성에 대해 글을 썼었는데, 한번 읽어보시는 걸 추천드리고 만약 틀린점이 있다면 제ㅔㅔ발 피드백 부탁드립니다.

암튼 iOS 12.2, watchOS 5.2 및 tvOS 12.2에서 실행되는 Swift앱은 자기가 Swift Dynamic Library를 들고 있지 않아도 된다!!

 더이상 포함하지 않는다!!! 이소리입니다.


자, 결과적으로 Swift앱은 size가 줄어들게 됩니다. 왜냐? Swift Dynamic Library를 더이상 포함 안하거등 ㅎ

아 얼른 앱 사이즈를 비교 해보고싶네요.


이제 본격적으로 Swift의 문법적인 변화를 살펴볼건데...다 쓸려면 뭔가 시간이 개오래걸릴 것 같으니 차근차근 쓰도록 할게요. 



SE-0192  Handling Future Enum Cases




사실 별거 없습니다. 


자 DJ라는 enum이 있죠? 그래서 해당 case에 맞게 print를 해주는 함수를 하나 만들었어요. 

그냥 뭐 대충 이해하셈

근데 만약에 저기에 뭐 음..case가 하나 더 추가된다고 생각해볼게요.

와 gist 진짜 귀찮네


자 이렇게 case에 marshmello가 추가되었습니다.

그래도 아무변화 없죠. 왜냐? chainsmokers와 marshmello는 명시적으로 검사(?)를 안해주니까 

default로 들어가겠고, 이건 전혀 이상하지 않죠.

네 지금까진 우린 잘 적응하고..있었죠.


하지만 이번에 약간의 변화가 생기는데요.

이게 히스토리를 알면 좋을 것 같아서..swift evolution문서를 읽어보았습니다.


3줄요약하면


1. 라이브러리의 새 버전에서 enum은 더 많은 case를 가질 수 있겠죠. 

Apple이 라이브러리 개발하다 보니까 버전 업되면서 추가해야하는 case들 몇개가 더 생긴거야!!


2. 자..그럼 라이브러리 작성자는 뭘 생각해야 할까요. 내가 이 case를 추가하는 것이 과연.. binary compatibility를 위반한다고 해야하나? 암튼 binary compatibility를 지키면서 새로운 case를 추가해야만 합니다.


3. enum을 철저히 구분짓는게 다들 좋죠..? 다 default로 들어가버리면 엉망되잔슴...


3줄요약 결국 안됐죠?

그니까 결국 enum의 catch-all case(예를들어 default, case _ 가 있겠네요.)에 

@unknown이라는 걸 앞에 붙이면, 컴파일러가 경고를 주게 변경되었습니다. 



이렇게요.



@unknown은 case중간에 올 수 없습니다. 무조건 마지막 case에만 와야하구요. 

catch-all case 앞에만 붙을 수 있습니다. 위에서 말했듯이 default나 case _ 에요.



우리가 catch-all case없이 나머지 case들을 명시 해주지 않으면 저렇게 에러가 났었죠?

그래서 모든 케이스를 구현해주거나, 저 상태에서 default를 추가해서 저 에러를 없앴잖아요 우리???


그냥 이렇게 default에 @unknown attribute(?)를 붙혀주면 warning이 나게 바뀐겁니다.

어떨 때? 우리가 명시적으로 검사 안한 케이스가 있고 그걸 default로 처리하도록 했을 때 ㅇㅇ



만약에 새로운 case가 추가됐으면 그 case에 맞는 행동을 하면 좋겠죠? 

그러니까!!!!!!!! Apple이 의도한 것은 이 @unknown attribute를 사용하면, 

정말 "미묘하게" 다른 2가지 시나리오를 구별할 수 있게 됩니다.


1. 이 default case는 개별적으로 취급하고 싶지 않기 때문에, 다른 모든 case(all other cases)에 대해 실행돼야해!

2. 모든 case를 개별적으로 처리하고 싶지만, 앞으로 어떤 문제가 발생할 경우 오류를 일으키기보단 이것(@unknown)을 사용해라.


그러니까 이 @unknown을 default case에만 붙힐 수 있잖아요?

그러면 2가지 시나리오가 나오겠죠?

이 default에 @unknown을 붙힌경우와, 안붙힌 경우. 

1번이 @unknown을 안붙힌경우고, 2번이 @unknown을 붙힌경우겠죠.

그래서 2번같은 경우엔 새로운 case가 추가되면, warning이 뜨도록 바뀐것이죠.

근데 과연 이게 유용할지.........유용할까? warning이 뜨는게 과연.........

하지만 만들어줘서 감사.



자 다음,,


SE-0200 Enhancing String Literals Delimiters to Support Raw Text




다른 많은 언어들 처럼, Swift역시 escape character인 "\"를 사용하고 있어요. string literal내에서 후속 문자(subsequent characters)를 특수하게 해석하는 기능(?)을 가지고 있어요.

 


자!! 예제로 봅시다.

본인이 귀찮은 관계로 지금부턴 모두 이미지다.

자 만약에 Swift 5.0 "이전에서" string안에서 "를 사용한다고 생각해봅시다.

만약에 Zedd : "안녕하세요 :) Zedd입니다."를 출력 해야한다고 생각해바



그럼 얘는 안녕하세요를 시작하는 "가 String이 끝난걸로 인식해버리죠.

그래서..이걸 인식하게 하려면



이렇게 "앞에 \를 넣어야만 \뒤에오는 "를 특수하게 인식해서...

우리가 원하는 

Zedd : "안녕하세요 :) Zedd입니다." < 가 나올 수 있게 되었죠.

이거 빡쳐 안빡쳐


암튼 이게 빡치는 사람들을 위해 Apple이...오구오구 해줬는데요



이렇게 String 양 옆을 #으로 감싸면 \를 사용하지 않아도 "가 잘 인식이 되는 것을 볼 수 있습니다. 짱인가..? 짱....짱이죠 뭐

고마워 애플

우리가 자주 \를 사용할 때는 String안에 변수가 들어갈 ㄸㅐ..



암튼 이건 많이 쓰죠? 

그럼 이럴 때는 어케하냐



이런식으로 하면 됩니다. ㅇㅋ?


SE-0215 Conform Never to Equatable and Hashable




직역하면..Never가 Equatable과 Hashable을 준수한다..! 정도가 되겠네요.

Never많이 쓰시나요?

저는 한번도 쓴적은 없는...그냥 예약어다..라고만 알고있는 수준입니ㄷㅏ..저는..

누가 저한테 Never가 므ㅓㄴ지 설명해봐라 하면 못할것같네요.

그러니까 공부해봅시다.


Never는 enum인데요, 


Swift 표준 라이브러리 안의 뭔가 디버깅하고..뭐 그런쪽의 



프로그램을 종료...시키는..그런 쪽과 관련이 있는 아이같네요. 

우리 Never는 몰라도 fatalError는 많이 봤죠? 

fatalError를 만나면..앱이 바로 종료되게 됩니다. 

그런 fatalError의 리턴타입이!!!!!!!!!

더이상은..Never......

암튼 fatalError의 리턴타입이 Never네요.


Never는 그냥 간단하게 생각하면 됩니다.

fatalError가 일어났다는건 뭔가 정상적이지 않은 동작이 일어났다는 거죠? 

Never는 "정상적으로 리턴하지 않는 함수(function)의 리턴 타입"입니다. 또한 값이 없는 타입입니다. 



이런식으로 사용할 수 있씁니다.

왜 return을 fatalError앞에 안적어줬지..? 

적어도 안적어도 같은 결과를 내는데요, Never는 뭐 그런 아이인가봐요?

아무튼 이게...Swift 5.0부터는.. Equatable과 Hashable을 준수하게 된다. 뭐 이게 변경사항입니다. 

아래는 이게 Swift 4.2




아래는 Swift 5.0




Never는 불가능한 코드(impossible code)를 나타내는데서 굉장히 유용하다고 해요.

대부분의 사람들은 fatalError의 리턴타입으로 익숙하지만, 

Never는 generic class로 작업 할 때 유용하다고 합니다.


예를 들어, Result 타입은 Value가 "항상" error임을 나타내거나, Error에서 error가 절대 발생하지 않는것을 나타내기 위해 "Never"를 사용합니다. 

(대문자로 시작하는건 타입입니다.)


아무튼 이렇게 바뀌었다고 하네요.

음................제가 Never를 안써봐서인지 확 와닿지가 않는데, 이 제안은 이따가 볼 Add Result to the Standard Library와 관련이 많습니다 :)



SE-0216 Introduce user-defined dynamically "callable" types



이건 잘 모르겠네요 일단 패스.

Swift 4.2때도 Dynamic member look up도 안쓰니까 뭐가 됐다는건지 다 까먹었네요.

이 callable도 dynamicMemberLookup과 관련있어요.

"This proposal is a follow-up to SE-0195 - Introduce User-defined "Dynamic Member Lookup" Types"

이렇게 말하고 있네요.

흠, 이건 나중에 보도록 할게요,.





SE-0218 Introduce compactMapValues to Dictionary



Swift4에서 Dictionary operation에 2가지가 새롭게 추가되었는데요, 

mapValues와 새로운 버전의 filter입니다.

얘네 둘은 Sequence에 있는 map과 filter와 대응하지만, 배열(array)가 아닌 Dictionary를 리턴합니다.

하지만..Dictionary버전의 compactMap은 도입하지 않았죠. 



자..이렇게 dictionary가 있다고 생각해봅시다.

여기서 value가 nil이 아닌거만 쏙 빼내고 싶어요.

결과적으로 ["a": "1", "c": "3"]을 만들고 싶다는 것이죠.


자..그럼 어떻게 해야할까요?



필터로 nil이 아닌것만 뽑아서..filter까지 적용된 상태는 value가 optional일거에요. 왜냐면 dic의 타입은 선언과 동시에 [String: String?]일테니까...

그래서 mapValues로 강제 언래핑을 해주면!  ["a": "1", "c": "3"]가 만들어질거에요. 


아래 r2가 만들어진거도 봅시다. reduce를 사용해서 dictionary를...만들어주었습니다.


r1, r2결과 모두  ["a": "1", "c": "3"]이 나올거에요.


다른 케이스를 한번 봅시다.



이런 dictionary가 있어요. 여기서 value가 Int로 casting(?)될 수 있는..

그니까  ["a": 1, "b": 2]로 만들고 싶어졌음



그렇다면 똑같이 위에 처럼 2가지 방법이 있삼

사실 mapValues를 아예 안써봐서요..........암튼 저런식으로 쓸 수 있네요.

암튼 코드 보면 아시겠죠?  둘 다   ["a": 1, "b": 2]가 나오게 됩니다.


암튼 우리가 하고싶은건 seqeunce에서의 compactMap과의 동일한 기능인데...dictionary에서 그 짓을 하려면 이렇게 코드가 아름답지 않았는데요,


Swift 5에서 그 기능이 제공되게 됩니다.

compactMapValues라는 이름으로요.

해볼까요? 

위에 중간에 nil 있던거...



 깔-끔



깔-끔



 애플 압도적 감사



SE-0220 count(where:)




드디어!!!!!!!!!!!!!!!

애플 바보야 왜 이제야./.왜...

제가 예전에 이 글에서 어이없는 경험을 한걸 공유했었는데..


Xcode : ㅇㅇExpression이 넘 복잡한부분이니 좀 분리하는걸 추천하는 부분임


암튼 이걸 보니 생각나서 올렸음..저 에러가 나던때는 Xcode9 이던 시절..


암튼 우리가 뭐 어떤 조건을 만족하는 element의 개수를 알고싶으면..




이렇게 해야했...

하지만..count(where:)만 있다면..?



깔-끔


우리프트의 생략을 이용하면..



lazy도 먹으니까 알아서 사용하시길.


애플..압도적 감사



오 이 SE의 리뷰어가 크리스 래트너네요

우리가 지금까지 본 SE중 래트너의 첫 등장..(리뷰어로서)

.

무슨짓을 하면 래트너가 다른곳도 아니고 구글로 가게 할 수 있지..?

래트너.......Swift는 계속 봐주실거죠...


암튼 다음 SE를 봅시다.


SE-0221Character Properties



String은 Character가 모여서 만들어진 거라는 건 감이 오시죠. 
그냥 String에 비해 Character로 할 수 있는게 적었는데, 이 제안을 통해 Swift에서 Character의 유용성과 프로그래밍 접근성을 높이기 위해 몇가지 쿼리를 추가했다고 합니다.
Swift 4.2기준으로..


zzzzzzzz 

Character로 쳐서 나오는 프로퍼티/메소드 저거밖에 없음 

스크롤 하면 더 나오는거 아니구요 저게 끝임


String만 많이 다뤄서..이렇게 Character가 String에 비해........적은지 몰랐음.

암튼 이걸 Swift 5.0에서는 좀 개선했다니까 봐봅시다.



오?? 일단 스크롤이 됨zzzzzz



뭐 문서 보면 이정도가 추가된 것 같네요.

아스키값 줘서 진짜 고맙다...

PS할 때 굉장히 유용해 질 것 같네요.

ㅋ-ㅋ



가장 유용할 수 있는...isWhitespaceisNewline도 추가됐네요.

감사합니다 애플..


SE-0224 Support 'less than' operator in compilation conditions




라이브러리나 패키지를 만드는 사람은 코드가 여러 버전의 언어로 작동됐음 좋을거겠죠?!

그래서 SE-0020처럼 (참고로 Swift 2.2때 나온 제안임)

뭐 이런게 있는데..


swift(>=4.2) 는 swift 4.2이상인거고.. !swift(>=4.2) 이렇게 앞에 느낌표를 붙혀주게 되면, swift(<4.2)가 되죠.

엥??? 왜저렇게 했대 그냥 swift(<4.2)이렇게 하면 되는 것을...





에러가 나거든 ㅎ
오직 >= 만 되나봄
암튼 #if !swift(>=4.2)...얼마나 드러워요. 느낌표가 있음으로써 굉장히 더러워보임.


근데 Swift 5.0에선..< 도 먹게 해놔따...이거임. 

하지만 <= 또는 > 는 고려하지 않을것이다..라고 하네요.





SE-0225 Adding isMultiple to BinaryInteger



"Adding isEven, isOdd, and isMultiple to BinaryInteger".


요약하면 이겁니다. 

이건 머 toggle()급 간단함


BinaryInteger가 머냐

얘는 프로토콜입니다. Integer들의 근간?이 되는 프로토콜임

Int는 물론이고 UInt, Int64뭐 이런애들은 다 이 BinaryInteger 프로토콜을 따르고 있습니다.


암튼 이 BinaryInteger에다가 isEven이랑 isOdd랑 isMultiple을 추가했다네여ㅛ.

그럼 즉 Integer애들은 얘네를 호출할 수 이따..


뭐 때로는 integer가 다른 integer의 배수인지 여부를 알아야 할 때도 있죠.. 

현재 값이 어떤 값의 배수인지 알려면??


12 % 2 == 0 // returns true. 12 is a multiple of 2.


%를 이용하곤 했었죠.


하지만..isMultiple얘네같은 애들이 나와서 가독성을 크게 향상시키죠.

연산자 우선 순위 규칙을 이해 할 필요도 없고 말이죠( %는 ==보다 우선순위가 높음)

이름도 isMultiple...얼마나 깔끔해


ㅋㅋㅋㅋㅋㅋ아니

문서 진짜 귀엽다


"The isEven and isOdd properties are also fewer characters wide than the remainder approach (maximum 7 characters for .isEven vs 9 for % 2 == 0) which saves horizontal space while being clearer in intent."


horizontal space를 절약 할 수 이따..!!!



깔-끔

*colour는 color의 영국식..


아니 근데 머지 isMultiple은 있는데 

isEven이랑 isOdd가 자동완성으로 안뜨네요? 아니 그니까 안뜰뿐더러 아예 없음..뭐지..

버그인것인가?



SE-0230 Flatten nested optionals resulting from 'try?'



이건 제가 예~~전부터 쓰고 있던 글이 있어서..이걸 다 쓰고 그 글을 발행하고..링크를 넣도록 하겠슴

https://zeddios.tistory.com/650

써따





SE-0234 Remove Sequence.SubSequence




뭐 아무튼 자세한건 설명안할건데, 

Sequence에서 위와같은 메소드들 많이 보셨죠?  

Sequence에서 SubSequence associated type을 제거하고, Collection에서부터 나타나도록 수정했다고 합니다.

그니까 원래는 Sequence에서 SubSequence associated type이였다면

이제는 Collection에서의 associated type이 SubSequence가 됩니다. 


Protocol에서 SubSequence를 리턴한는 Sequence의 메소드를 제거하고


위와같이 변했다..라는 소리같습니다.


아래가 Swift 4.2




아래가 Swift 5.0입니다.




Sequence.SubSequence에 의존하는 코드가 더 이상 작동하지 않는다는 점에서 source-breaking인 변화입니다. 

역시나 이는 ABI-breaking인 변화이기도 합니다. 

위와같은 코드는 더이상 작동 하지 않을 거에요.





SE-0235 Add Result to the Standard Library



제가 위에서 Never설명 할 때 이 제안이랑 관련이 있다고 했는데,

이 쓰레드(Conform Never to Equatable and Hashable)에서 왜 관련이 있는지..등등이 나오게 됩니다. 

이 제안 역시 리뷰매니저가 래트너네요

방가방가


이런 코드..많이 보셨을겁니다.



ㅇ위 코드는 https://github.com/Alamofire/Alamofire/blob/master/Source/Result.swift

너무나ㅣ도 유명한 Alamofire의 Result.swift입니다. 여기서 Result타입을 직접 구현하여 여기저기서 사용하고 있죠. 

뭐 alamofire가 아니더라도..Result는 Swift커뮤니티에서 정말 일반적으로 사용되는 타입이죠. 


이 쯤되면 이 제안이 뭘 추가했는지 감이 오시나요?

Swift 라이브러리에 이 Result타입이 추가되었습니다.



구현은 위와 같이 생겼네요.


이런식으로 사용 가능



Result라는 스타가 2천개 되는 라이브러리인데요

따흑

Alamofire는 과연 어떻게 바뀔지? 


애플 이런 변화 너무 좋아

공부 할 맛이 난달까

이 많은 제안서들 중 가장 하이라이트가 아닐까 생각이 드네요ㅋ_ㅋ



자 이렇게 공부를 마치려고 하는데, 물론 아직 모르는 거도 많...

데 음..SE에서 Status가 Implemented (Swift 5)라고 적힌거만 공부중인데, 아직 정식 릴리즈가 안됐으니..

그럴일은 없다고 보지만 틀린 내용이 있을 수도.

그리고 제가 애플의 변화 의도와 다르게 해석(?)했다고 해야하나 그런게 있으면 꼭 댓글 남겨주시기 바랍니다.


그리고 Implemented (Swift 5)라고 적힌거지만 짜친거는 추가 안함

하지만 시간이 난다면 설명은 안하고 이런거 있다 링크는 추가할게요

드디어 발행한다....드디어


반응형

'Swift' 카테고리의 다른 글

Swift로 PS할 때 유용한 메소드들  (0) 2019.03.02
Swift 5 ) Flatten nested optionals resulting from 'try?'  (1) 2019.02.18
Swift Snapshot써보기  (1) 2019.01.07
Swift 5.0 Release Process  (3) 2019.01.04
Swift ) Swift Sorting Algorithm  (4) 2018.12.26