티스토리 뷰

공부

WWDC 21 ) Meet TextKit 2

Zedd0202 2021. 7. 18. 17:40
반응형

 

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

예전에 WWDC 18) TextKit Best Practices볼 때

설명 찰떡같이 하시고...포스가 엄청나서 멋있다고 생각했는데, 이번 WWDC 21 ) Meet TextKit 2에서도 볼 수 있어서 너무 좋다 😍

 

# TextKit 2

🙋: TextKit 2라면 1도 있겠구만..

🧑‍💻 : ㅇㅇㅋ. TextKit 1 == Text Layout과 Display를 구동하는 Text 엔진 (in 모든 Apple 플랫폼에서)

UIKit, AppKit의 Text Control은 TextKit 1을 사용하여 Storage관리 / Text Contents Layout을 제어함

 

🙋: TextKit 2 는 갑자기 왜낸거..ㅎ

🧑‍💻: TextKit 1 나온지 진짜 개오래댐 ㄹㅇ;;; 20년 넘음;;;;;;

근데 이 20년이라는 시간동안 아키텍쳐, 엔지니어링 원칙 이런게 많이 바뀌었자나 ㅇㅇ

근데 TextKit 1 얘가

1. 옛날 원칙에 묶여있음

2. 근데 높은 성능으로 제공해야함

3. 또 최신 기술과도 잘 통합이 되어야함

==> 점점 더 어려워짐..

🍎 : 그래서 TextKit 2 함 만들어봤어 ㅎ

TextKit 2 == 미래지향적인 디자인 원칙을 기반으로 구축된 Apple의 차세대 Text 엔진.

몰라겠지만 macOS 11 부터 이미 TextKit 2를 쓰고 있음 👏

 

🙋 : 그럼 TextKit 1은...??

🧑‍💻 : TextKit 2는 1이랑 공존할거임. 

TextKit 2는 1과 마찬가지로 Foundation, Quartz 및 Core Text를 기반으로 구축됨.

 

🙋 : TextKit 1도 개같았는데...TextKit 2도 어렵겠지..ㅜㅜ..

🧑‍💻 : ㄴㄴ아님. TextKit 1 진짜 개같았던거 인정;;;; 근데 TextKit 2는 진짜진짜 쉽게 할 수 있도록 해놨음.

 

# Glyphs

Glyphs에 대해서 잠깐 설명.

iOS ) Typographical Concepts 글도 참고하면 좋을 듯. 

🧑‍💻 : Character 알지? "Character A"하면 어떤 A가 생각나? 

🙋: 으음 정갈한 고딕체의 "A"가 머리속에 그려지는 군..

🧑‍💻 : 너가 상상한 정갈한 고딕체의 "A"는 Glyphs야 ㅎ

🙋: ⁉️

Character는 추상적인 개념이며, Character는 여러 size, 두께 등으로 그려질 수 있음.

이런 다양한 형태의 특정 character중 하나를 글리프(glyph)라고 하는 거. 

위 그림은 Glyphs of the character A. 즉, Character A에 대한 Glyph들임. 

자 근데 생각해보자. 

보통 서양 언어에서는 하나의 glyph가 하나의 character를 나타내지만, 항상 그런게 아님. 

왼쪽 그림처럼 단일 character가 여러개의 glyph를 가질 수도 있고, 

또 그 반대로 

오른쪽 그림 처럼 여러개의 character가 하나의 glyph로 나타내지기도 한다.

오른쪽 그림을 보면, 

여러개의 character가 하나의 glyph로 합쳐진것으로 보이는데,

이런걸 합자(Ligature)라고 함. 

 

[보통 서양]

- 합자 별로 안많음.

- 합자가 일반적으로 텍스트의 가독성에 영향 X

 

[아랍어, 데바나가리 문자와 같은 스크립트]

- 합자 개많음

- 가독성에 영향 미침.

(한번에 이해)

 

# Design Principles

TextKit 2는 다음과 같은 핵심 디자인 원칙을 가지고 있음. 

1. Correctness

2. Safety

3. Performance

 

# Design Principles - Correctness 

1. Apple Device는 전세계 어디에서나 쓰임.

2. 전세계에는 많은 언어들이 있음 

==> 모든 언어와 스크립트로 된 텍스트에 대해서 올바른 레이아웃, 렌더링, Interaction을 제공하는것이 중요. 

위에서 봤듯이 

이런거..잘 대응해 줘야함. 

 

[보통 서양언어]

올바른 glyph범위 파악하는게 나쁘지 않음. Character Range가 곧 Glyph Range되는거

 

[ex. 칸나다어(인도)]

- 합자 개많음.

- Glyph를 재정렬하고 완전 흥미로운 방식으로 결합도 가능. 

 

핵심은!!!!

처음 4개의 Character에 대한 glyph 범위를 찾을 수가 없음. 

근데 TextKit 1에서는 

** 뭔 API 쓸라고 하면 glyphRange 넘겨줘야됨;;;;; 하

위에서 이야기 한 것 처럼 glyphRange를 찾을 수 없을 때 위와같은 API를 사용하면 레이아웃 및 렌더링이 잠재적으로 중단될 수 있었음.

 

[TextKit 2] 

- 모든 Text를 Core Text로 렌더링 복잡한 스크립트에 대해 자동으로 올바른 렌더링을 얻을 수 있음.

- glyph처리를 추상화함. glyph를 전혀 관리할 필요가 없음. 상위 level 객체를 사용하여 레이아웃 및 Interaction을 제어함. 

 

# Design Principles - Safety

 Swift / SwiftUI와 같은 기술의 목표에 더 잘 부합하도록 Value semantic에 더 중점을 두고 TextKit 2를 설계.

🙋 : 오잉..TextKit 2 내부는 뭐 class가 아니라 struct로 만들어졌나?

🧑‍💻 : Value semantic ≠ Value Type. Value semantic이 Value Type을 말하는 것이 아님.

그니까 NSLayoutManager같은 타입이 struct로 만들어졌다는 뜻이 ㄴㄴ

Value Type은 데이터의 고유 복사본을 유지하여 해당 데이터의 변형을 방지. 

의도하지 않은 사이드 이펙트 제거  코드를 안전하게 만듬.

오직 Value Type이 이러한 이점을 얻을 수 있는게 아님

Immutable classe는 Value Type처럼 동작하므로, value semantics이라 나타낼 수 있음.

Immutable classe같은 것들은 데이터를 변경하려면 원본 인스턴스를 대체할 완전히 새로운 인스턴스를 만들어야 한다. 

TextKit 2의 많은 클래스가 이런 방식으로 설계되어 있음. 

 

TextKit 1에서 Text 흐름을 보자.

1. Text Storage에 대한 업데이트를 Layout Manager에게 알림.

2. Layout Manager는 glyph를 생성, 위치 지정, View에 직접 그린다.

🧑‍💻 : glyph를 View에 직접 그리는 방식을 사용하면, custom draw를 위한 공간을 만들기 위해 Text를 분리할 위치를 파악하기 어려움.

🙋 : ....??

 🧑‍💻 : ㅇㅋ

지금 나머지 텍스트는 다 똑같은데 딱 저기에 저런 남색 배경 && 흰색 텍스트를 넣어서 보여주싶어.

그럼 어떻게 해야할까? 

🙋 : 그냥 저거 만들어서 저기에 insert하면 될 삘..? 

1. 저 Text들을 일단 나누고

2. 내가 넣고 싶은 텍스트를 추가해! (NSTextStorage에 넣겠지..?)

3. LayoutManager에서 위치도 지정해주자!

4. 저게 남색 배경 && 흰색 텍스트로 나와야하니까 어떻게 그릴지도 넣어주자~

🧑‍💻 : 응 근데 TextKit 1에서 그렇게 하면

개망함 ㅅㄱ

🙋 : **

🧑‍💻 : 근데 그걸 TextKit 2가 해냅니다.

 

TextKit 2에서는

대충 이런식으로 흘러감.

1. Text Storage에 대한 업데이트는 Text Content Manager라는 객체를 거침

Text Content Manager는 Text를 Text Element로 나누고 추적함.

2. Layout을 해야할 때가 되면, Text Layout Manager는 Text Content Manager에게 Element를 요청.

3. Text Layout Manager는 Element를 Text Container에 배치하고, Layout 및 위치 정보가 포함된 Layout Fragment를 생성.

4. Display를 해야할 때가 되면, Layout Fragment가 Viewport Layout Controller에 전달되어 View or Layer에 해당 Fragment의 위치와 Layout을 조정함. 

 

 🙋:  Value Semantic...??

🧑‍💻 : 여기서 Value Semantic이 강조되는데,

Value Sematic을 사용하는 객체에서 필요한 정보를 얻어, 텍스트의 레이아웃과 Display를 제어할 수 있음.

내가 Text Layout Fragement를 변경하고 싶으면,

내가 원하는 변경사항으로 Text Layout Fragement인스턴스를 새로 만들고,

그걸 시스템에 다시 제공하면 됨.

 

🙋 : 그럼 TextKit 2로 한다고 치면, 아까

✅ 1. 저 Text들을 일단 나누고 → NSTextElement로 이미 나눠져 있음. 

✅ 2. 내가 넣고 싶은 텍스트를 추가해! → NSTextElement를 만들어서 추가해줌 

3. LayoutManager에서 위치도 지정해주자!

4. 저게 남색 배경 && 흰색 텍스트로 나와야하니까 어떻게 그릴지도 넣어주자~

2번 Step까지 된거네..? 

 🧑‍💻 : ㅇㅇ 맞음. 이제 위치를 지정해보자. 

NSTextLayoutManager  →  Text Layout 프로세스 제어. 

TextKit 1의 NSLayoutManager와 비슷하지만, NSTextLayoutManager는 glyph를 처리하지 않음. 

아까도 말했듯이 TextContentManger에서 Text Element를 가져와서,

ext Container에 배치하고 NSTextLayoutFragment를 생성함.

그러니까 나는 새로운 TextLayoutFragment 인스턴스를 만들어서 시스템에 전달해주면 됨.

NSTextLayoutManagerDelegate를 사용하여 레이아웃 프로세스에 연결하면 됨.

이 step에서 

1. 저 Text들을 일단 나누고 → NSTextElement로 이미 나눠져 있음.

✅ 2. 내가 넣고 싶은 텍스트를 추가해! → NSTextElement를 만들어서 추가해줌 

✅ 3. LayoutManager에서 위치도 지정해주자!

✅ 4. 저게 남색 배경 && 흰색 텍스트로 나와야하니까 어떻게 그릴지도 넣어주자~

3, 4번이 모두 해결됨. 

 

그니까 Safety쪽의 핵심은 모두 새로운 인스턴스를 만들어서 바꿔치기(?) 해주니까 안전하다~이런 것 같음. 

 

# Design Principles - Performance

마지막. 성능!

- 성능은 Text 엔진에서 가장 큰 과제 중 하나.

- TextKit 2는 스크롤 되는 수백 MB에 달하는 문서 레이아웃 등 다양한 시나리오에서 개빠름

이럴려면 비연속적인 텍스트 레이아웃(noncontiguous text layout)이 필요함

🙋 : noncontiguous text layout..?

🧑‍💻 : contiguous layout VS noncontiguous layout.

 

[contiguous layout]

이렇게 있다가 스크롤을 쭉 해서 오른쪽 사진 처럼 됐다? 

그럼 텍스트가 시작한 처음부터 스크롤 지점 이전에 있던 모든 텍스트에 대해 contiguous layout이 layout을 수행하게 됨. 

화면에서 스크롤 된 모든 텍스트를 layout하는거라서 텍스트가 많으면 

성능이 느려지고, 스크롤 애니메이션이 이상해질 수 있음. 

 

[noncontiguous layout]

noncontiguous layout은 맨처음부터 시작하는게 아니라 보이는 부분(Visible area)에 대해서만 Layout을 수행.

성능 향상

 

TextKit 2의 레이아웃은 항상 noncontiguous layout.

반대로 TextKit 1에서 noncontiguous layout은 Optional임.

🙋 : 그럼 TextKit 1에서도 저 프로퍼티 무조건 true로 하면 좋은거 아냐?

🧑‍💻 : 이게 너무 간단하게 구현되어 있어서;; 문서의 어떤 부분이 배치되는지 제어하는 기능 X

레이아웃이 완료되고 실제로 업데이트 되는 시기도 알 수 없음. 

TextKit 2는 Visible Area에 대한 일관된 Layout 정보를 제공 && Layout이 업데이트 되는 시기도 알 수 있음. 

이 영역을 View Port라고 함.

View Port를 조정하거나 재배치하여 관리하고 View Port 레이아웃 전, 도중, 후에 Callback을 받음.

그게 Flow의 마지막 과정이고, Callback은 Delegate메소드를 통해 받을 수 있음.

그냥 TextKit 2에서는 noncontiguous layout 사용한다는 것이 성능쪽의 핵심인 것 같음. 

 

TextKit 2에서 새로나온 클래스에 대한 설명은 다 생략했으니

WWDC 21 ) Meet TextKit 2를 한번 쫙 보는 것을 추천!

아 옛날에 WWDC 13 ) Introducing Text Kit을 보면서 TextKit에 대한 글을 썼었는데...

지금 보니 너무 못봐주겠어서 비공개 처리합니다...

TextKit 1에 대한 설명을 보고 싶으시다면 위 WWDC를 보시는 것을 추천!

 

참고

WWDC 21 ) Meet TextKit 2

반응형

'공부' 카테고리의 다른 글

Swift Concurrency와 Combine  (3) 2021.09.04
IDFA 관련 기록  (0) 2021.08.01
MetricKit 톺아보기  (3) 2021.07.11
WWDC 21 ) Meet the UIKit button system  (3) 2021.07.04
WWDC 21 ) Adjust Your Layout with Keyboard Layout Guide  (2) 2021.06.18