스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
AppKit의 새로운 기능
Mac 앱 개발의 최신 업데이트를 살펴보세요. 컨트롤과 메뉴에 대한 개선 사항을 공유하고, 뷰 경계에서 벗어나도록 도와줄 수 있는 툴을 탐색합니다. 사용자 인터페이스에 움직임을 추가하는 방법, 텍스트 입력 개선 사항을 이용하는 방법, 기존 코드를 Swift 및 SwiftUI와 통합하는 방법에 대해 배워보세요.
챕터
- 1:00 - Controls
- 5:31 - Menus
- 9:19 - Cooperative app activation
- 11:16 - Graphics
- 18:04 - Graphics: Images
- 20:54 - Text improvements
- 23:43 - Swift and SwiftUI
리소스
관련 비디오
WWDC23
-
다운로드
♪ ♪
안녕하세요 저는 Aasim Kandrikar입니다 본 세션 후반에는 Raleigh Ledet이 함께할 건데요 저희는 AppKit 팀의 엔지니어입니다 본 영상에서는 macOS Sonoma의 새로운 AppKit 기능을 소개할게요 다양한 주제에 대해 다룰 예정인데요 우선 AppKit Controls의 API 개선점과 새로운 기능부터 신규 implementation으로 동작하는 메뉴의 개선 사항 macOS에서의 앱 활성화 방식의 변화 그래픽 개선 사항과 새로운 이미지 및 심벌의 기능 새로운 텍스트 입력 경험과 비영어 언어들에 대한 텍스트 레이아웃 변화 Swift와 SwiftUI 내 작동 개선 사항까지 다뤄볼게요
macOS Sonoma에서는 새로운 기능들과 AppKit 컨트롤에 대한 API 개선점을 다룰 겁니다 NSTableView와 NSOutlineView는 특별한 기능을 다수 제공하여 AppKit를 이용한 Mac 앱을 디자인하는 중요 요소가 됩니다
macOS Sonoma에는 컬럼 사용자화 메뉴 제시 API가 추가됐는데요 이 메뉴에서는 사용자가 테이블 컬럼 가시성을 토글할 수 있죠 이전에는 이 메뉴를 만들고 나타내려면 사용자 지정 구현이 필요했었죠 하지만 이제는 코드 단 세 줄만으로 가능해졌습니다 새로운 대리자 메서드인 tableView userCanChangeVisibilityOf를 사용하세요 숨길 수 있는 컬럼을 지정하고 AppKit는 메뉴 로컬라이징과 재실행시 숨겨진 컬럼 상태 복원 등 나머지를 처리합니다
Foundation의 Progress 타입은 앱이 수행하는 작업을 나타내죠 앱에서 다운로드가 진행 중임을 나타내기 위해서나 이미지가 처리되는 것을 나타내기 위해 사용됩니다 macOS Sonoma에서는 NSProgressIndicator와 함께 Foundation의 Progress 타입을 사용할 수 있습니다 새로운 observedProgress 프로퍼티에 해당 진행을 할당하면 진행 인디케이터는 백그라운드 스레드에서도 진행 상태가 변할 때 그 값을 업데이트합니다
버튼 베젤 스타일 API가 업데이트되었는데요 신규 베젤 스타일부터 시작해 자동화되었습니다 이 베젤 스타일은 버튼의 콘텐츠와 뷰 계층에서의 위치에 따라 최적의 스타일에 맞게 조정하죠 가령 버튼이 창에 있다면 푸시 버튼 스타일을 선택할 겁니다 툴바에 있는 경우에는 툴바 스타일을 선택하고요 긴 콘텐츠의 경우 플렉서블 푸시 버튼 스타일을 선택할 겁니다 자동 베젤 스타일은 모든 버튼 생성자에 대한 기본 베젤 스타일입니다
기존 베젤 스타일명은 모습에 관한 설명에서 시맨틱 사용을 기반으로 하여 현대적인 이름으로 업데이트되었습니다 이전에는 'Recessed'였던 버튼의 이름은 'Accessory Bar' 버튼으로 수정되었고요 이는 베젤 스타일이 액세서리 바에서 가장 흔히 사용되기 때문이죠 권장하지 않는 베젤 스타일은 이제 지원되지 않습니다 지원 중단의 경우 명료한 시맨틱 사용이 가능한 대체 베젤 스타일을 참조하죠 신규 스플릿 뷰 타입 인스펙터도 도입했습니다 인스펙터는 문서에서 현재 선택 콘텐츠의 맥락 정보를 보여주는 후행 스플릿 뷰 항목입니다
사이드바와 유사하게 전체 크기 콘텐츠 뷰 마스크가 설정되면 창의 전체 높이를 사용합니다 새로운 인스펙터는 macOS Big Sur로 이전 배포합니다 앱에 인스펙터를 추가하는 건 간단한 작업입니다 새로운 inspectorWithViewController 생성자를 사용하여 새로운 스플릿 뷰 항목을 만들고 기존 스플릿 뷰 컨트롤러에 새 splitViewItem를 추가하세요 다음으로 툴바 대리자를 업데이트하여 새로운 토글 인스펙터 툴바 항목을 포함시키세요 일반적으로 다들 토글 인스펙터 항목을 창 후행 가장자리에 있는 인스펙터 위에 배치하고 싶어 하시는데요 그렇게 하려면 토글 인스펙터 항목 전에 새로운 인스펙터 추적 구분자와 유연한 공간을 추가해 주세요
우리는 NSPopover에도 약간의 개선을 했습니다 먼저 툴바 항목에서의 팝업 고정 지원을 추가했죠 전체 크기 팝업 콘텐츠를 지원하는 방법도 추가했고요 뷰가 전체 팝업 바운드를 채울 수 있게 됐습니다 툴바 고정부터 시작해 볼게요 툴바 항목과 관련된 팝업을 나타내는 새로운 방법인데요
툴바 항목이 오버플로우 메뉴에 있는 경우 팝업은 오버플로우 쉐브론에 고정된 채로 우아하게 나타나죠
다음으로 팝업 콘텐츠는 체브론으로 확장 가능합니다 유색 백그라운드 헤더 뷰 팝업이 있었다면 이렇게 보였을 겁니다 헤더 백그라운드에 있는 색상은 쉐브론으로 확장되지 않죠 팝업 콘텐츠를 쉐브론 영역으로 확장하기 위해 새 hasFullSizeContent 프로퍼티 값을 true로 설정하세요 사각형 안전 영역을 사용해 눈에 띄지 않아야 하는 콘텐츠를 배치해 보시고요
그럼 이제 Raleigh에게 넘겨 Menus의 변화를 볼게요 Aasim, 고맙습니다 Menus은 Cocoa 완전 사용을 위해 다시 쓰여졌습니다 이로써 상당한 메모리와 CPU 사용량을 줄여 AppKit의 탄소 발자국을 감소시켰는데요 새로운 기능도 작동하게 합니다
구체적으로 섹션 헤더와 팔레트 메뉴 새로운 선택 동작과 배지에 대해 다뤄보려고 합니다 이 기능들은 새로운 기회를 열어주고 작성해야 하는 코드의 양을 줄여줄 겁니다
섹션 헤더는 메뉴에서 그룹을 보여주는 데에 도움이 되는 추가 기능으로 코드 한 줄로 만들어집니다 새 클래스 함수 sectionHeader(title:)를 사용해 하나 만들고 다른 메뉴 항목처럼 이걸 메뉴에 추가하세요 이 예시에서는 메뉴 섹션이 세 개 만들어지는데 각각 하나의 섹션 헤더와 두 개의 항목을 가집니다
팔레트 메뉴는 항목들이 수평으로 배치된 메뉴를 구축할 수 있게 해주는 아주 멋진 새 기능이죠 이 단순한 컬러 피커를 예로 들어보죠
어떤 메뉴든 팔레트 메뉴로 바꿀 수가 있는데요 메뉴의 presentationStyle을 .palette로 설정하면 가능합니다 각 메뉴 항목에 대해 이미지를 설정하세요 템플릿 이미지의 경우 AppKit는 자동으로 적절한 선택 단위를 추가합니다 아니면 offStateImage와 onStateImage를 설정할 수 있는데요 onStateImage는 선택을 나타내기 위해 사용됩니다
여러분이 선택할 수 있는 선택 모드에는 두어 개가 더 있습니다 .selectAny는 개별 메뉴 항목 상태를 토글하지만 그룹 내 다른 항목의 상태를 바꾸진 않습니다 .selectOne은 선택 메뉴 항목 상태를 on으로 설정하며 그룹 상태의 다른 멤버들은 off로 설정하죠 selectedItems 프로퍼티를 통해 온 상태로 설정할 항목을 얻거나 선택할 수 있습니다 참고로 selectionMode와 selectedItems는 논리적 그룹에 동일 타겟/액션 쌍을 가지는 메뉴를 구성하여 작동하죠 직접 만들 때는 각 항목에 동일 타겟/액션 쌍을 주어 selectionMode와 selectedItems 동작을 이용해 보세요 팁은 이게 팔레트 메뉴에만 제한되지 않는다는 겁니다 보통의 메뉴에서 동일 타겟/액션 쌍을 가진 메뉴 항목들에도 작동하죠 NSMenu는 공통 팔레트 메뉴를 만들 수 있는 convenience 함수를 제공합니다 색 정렬은 팔레트 항목의 숫자와 착색을 결정하죠 타이틀은 접근성을 위해 사용되기 때문에 꼭 추가해 주셔야 합니다 옵셔널 템플릿 매개변수는 착색에 어떤 이미지를 사용할지 지정합니다 예를 들어 여기서는 깃발 심벌 이미지가 사용됐는데요
템플릿을 지정하지 않으면 AppKit는 채워진 원으로 기본 설정할 겁니다 또한 옵셔널 클로저 매개변수도 있는데요 이 클로저는 사용자가 팔레트에서 메뉴 항목을 토글할 때마다 호출됩니다 Menu가 클로저에 통과됩니다 여기서 여러분은 selectedItems 프로퍼티와 함께 온 상태 메뉴 항목들의 배열을 얻을 수 있죠
메뉴 항목의 배지는 다양한 방식으로 부여됩니다 단순 문자열이나 count를 사용할 수 있죠
특별 카운트 배지가 세 개 있는데요 새 항목, 알림 업데이트입니다 이 배지 중 하나를 사용할 경우 AppKit는 자동으로 적절한 텍스트를 추가합니다 또한 텍스트를 적절하게 로컬라이징하죠 이건 일본어 예시입니다 하지만 메뉴 항목 자체와 일반 문자열 배치 변형을 로컬라이징해야 하죠
그것은 완전히 새로운 메뉴 구현입니다 퍼포먼스 개선, 배지 팔레트, 섹션 헤더까지 말이죠
macOS Sonoma에서 우리는 협력 앱 활성화를 도입했습니다 이건 예상치 못한 앱 간 전환을 줄여줍니다 가령, 타이핑 중간에 앱 전환이 일어나는 경우를요
협력 앱 활성화에는 두 가지 부분이 있는데요 activate는 이제 명령의 반대인 요청입니다 시스템은 뭘 하고 있는지 더 넓은 맥락에서 고려하는데요 activate 요청이 적절한지 결정하기 위해서 말이죠 새로운 API는 앱이 미래 활성화 요청의 맥락에 영향을 줄 수 있도록 합니다
activate는 요청이기 때문에 ignoringOtherApps 매개변수와 옵션은 무시되죠 그래서 macOS Sonoma에서는 activate(ignoringOtherApps:) 함수와 activateIgnoringOtherApps 옵션 지원은 중단됐습니다 NSApplication과 NSRunningApplication라는 새로운 활성화 API로 대체하세요
활성 앱만이 활성화 맥락에 영향을 줄 수 있는데요 타겟 앱이 활성화되기 전에 명백한 타겟 앱으로 대체함으로써 가능합니다 타겟 앱이 활성화를 요청하면 시스템은 결정을 내릴 때 양보를 맥락의 일부로 사용하죠 요청이 받아들여지면 활성 앱은 비활성화되고 타겟 앱이 활성화됩니다 그렇지 않으면 활성 앱은 활성 상태를 유지하죠 NSWorkspace는 URL이나 앱을 열 때 이를 자동으로 처리해 줍니다
활성화를 직접 다른 앱으로 넘기기 위해서는 타겟 NSRunningApplication나 번들 식별자에 양보하세요
시스템은 타겟 앱이 활성화 자체를 요청할 때 양보 맥락을 사용하게 될 겁니다 아니면 자체적으로 활성화가 되죠 이게 새로운 협력 앱 활성화 동작입니다 우리는 macOS Sonoma의 그래픽와 드로잉에 많은 걸 변경했고 새 API도 추가했습니다 NSBezierPaths에서 CGPaths를 만들거나 그 반대도 가능하죠 NSBezierPath는 새로운 생성자 init(cgPath:)와 cgPath 프로퍼티를 얻습니다 cgPath를 초기화하거나 설정하거나 얻게 되면 항상 경로의 복사본을 만들어 냅니다 NSBezierPath의 추가 변화는 본래 또는 복사된 CGPath 인스턴스에는 반영되지 않습니다 즉 자유롭게 호환되지 않는다는 겁니다 이 추가에서는 CGPath API와 NSBezierPath를 사용했는데요 CAShapeLayer의 path 프로퍼티처럼요 코드 한 줄일 뿐이죠 이제 macOS에 CADisplayLink 오브젝트를 만드실 수 있습니다 이건 iOS에서 익숙하실 CADisplayLink와 동일합니다 이건 앱이 드로잉을 디스플레이 화면 재생률에 동기화시키게 하는 타이머 오브젝트입니다 직접 생성 오브젝트는 메인 디스플레이와 동기화되지만 macOS는 단일 디스플레이에만 제한되지 않습니다 따라서 macOS에서는 새로운 displayLink(target:selector:) 함수와 함께 NSView나 NSWindow, NSScreen에서 디스플레이 링크 오브젝트를 얻을 수 있습니다 최고의 방법은 가장 구체적인 적용 가능한 요소 보통은 창인데 여기에서 CADisplayLink 오브젝트를 얻는 거죠 이건 뷰나 창에서 만들어질 때 CADisplayLink는 창이 데스크톱 주변을 움직일 때 창이 어떤 디스플레이나 뷰에 있건 자동으로 추적합니다 디스플레이에 없으면 자체 중단되는 것도 말이죠
이 뷰 서브클래스에서 코드 두 줄로 startAnimating이 호출되면 DisplayLink 개체를 만들어 stepAnimation 함수를 호출합니다 이건 뷰가 어느 디스플레이에 있건 동기화되죠 startAnimating은 공통 모드의 메인 런루프에 displayLink를 추가합니다
이건 애니메이션이 완성되면 invalidate를 호출하여 디스플레이 링크를 멈추고 모든 등록 런루프 모드에서 제거하죠
NSColor는 이제 백그라운드 쉐입을 채우는 새로운 시스템 색상 5가지를 제공합니다 채우기 색은 다양한 크기의 쉐입에 따라 다양한 강도를 제공합니다 슬라이더 트랙이나 프로그레스 바 백그라운드의 스케일에 있는 더 작은 쉐입의 경우 돋보이기 위해 시스템 채우기나 2차 시스템 채우기 같은 더 높은 수준의 강조를 사용합니다 그룹 박스와 폰트 백그라운드 같이 더 큰 쉐입의 경우 더 미묘한 강도를 선호합니다 4색이나 5색 시스템 채우기처럼요 이 채우기 색들은 역동적이어서 다양한 모습에 자동으로 조정합니다 대비 증가 및 다크 모드를 포함해서요 커스텀 UI 요소를 빌드한다면 이 새로운 채우기 색상은 시스템 디자인에 맞고 접근성을 지원하는 편리한 방식입니다
NSViews는 드로잉 콘텐츠를 바운드에 맞게 자릅니다 그래서 간혹 드로잉이 원하는 대로 보이지 않죠 FreeForm 경고 창에 있는 이 힌디어 문자 하단처럼요
이게 발생할 수 있는 흔한 곳으로는 폰트 렌더링이나 쉐도우 기타 서브뷰 액센트입니다 배지나 세일 '핫' 아이템에 붙어 있는 불꽃처럼요 해결 방법은 두 가지입니다 더 큰 뷰에 있는 형제를 통합 뷰로 삽입하세요 하지만 테크닉마다 결점이 있기 마련이죠 이 경우 부모 뷰를 단일 수평 스택에 있는 버튼과 결합하면 기본적으로 텍스트의 기준선이 일치하지 않습니다 또 다른 문제를 해결해야 하는 거죠
더 나은 방법이 있습니다 macOS Sonoma에서 연결 시 대부분의 NSViews는 기본적으로 더 이상 바운드에 맞게 잘리지 않습니다
적중 테스트는 변화 없이 그대로 남아 있고 뷰의 기하학적 구조에 의해 결정됩니다 당연히 이걸 바꾸기 위해 hitTest 재정의가 가능합니다 뷰가 바운드 밖으로 그려질 수 있기 때문에 계산된 visibleRect는 바운드를 지나 확장됩니다 visibleRect를 사용한 코드를 검토하고 그에 따라 조정하세요 이는 draw 함수의 dirtyRect 매개변수에도 영향을 줍니다 구체적으로 말하면 dirtyRect는 뷰 바운드에 제한되지 않죠 AppKit는 뷰 바운드보다 큰 dirtyRect를 통과할 수 있는 권리를 보유합니다 드로잉을 필요한 만큼 많은 사각형으로 세분할 수 있는 권리도 보유하고요 이는 dirtyRect를 사용해 어디에 그릴지가 아니라 무엇을 그릴지 결정해야 한다는 겁니다
이건 예상치 못한 드로잉 결과가 발생한 예시인데요 이 draw 재정의는 dirtyRect에 통과 색을 배경색으로 재정의해 채우기 색이 뷰 바운드의 바깥으로 흘러 창 내 다른 UI도 덮어버리게 만들죠 이 뷰는 dirtyRect를 사용해 프레임을 그리지 않았습니다
이와 같이 배경 채우기 색은 더도 말고 덜도 말고 디자인이 필요로 하는 색으로 정확하게 채워야 합니다
dirtyRect 밖에서 그리는 게 항상 안전하죠 dirtyRect의 퍼포먼스 이점은 이 패스에서 드로잉을 피할 수 있는 데이터 부분을 결정할 때 발생합니다 제 이름으로 된 스트로크 패스를 계산하기는 힘들겠네요 dirtyRect가 그저 이 작은 코너라면 텍스트 프레임을 교차하지 않을 겁니다 그래서 뷰는 이 힘든 계산을 피할 수 있겠죠 백그라운드와 프레임은 여전히 그려져야 하죠 하지만 전체 바운드를 채우고 전체 프레임을 그리는 건 뷰에 이미 그려진 다른 부분에 영향을 주지 않을 겁니다 AppKit는 드로잉을 dirtyRect에 맞게 자르니까요
새로운 NSView .clipsToBounds 프로퍼티도 이용 가능합니다 OS X Mavericks 10.9에서도요 하지만 오래된 Os에서 .clipsToBounds를 끄면 가장자리가 거칠 수 있습니다 이에 따라 테스트 해보세요 클리핑 활성화 여부 관계 없이 뷰 동작 대부분 괜찮을 겁니다 일부 컨테이너 뷰는 자체적으로 명시적인 결정을 내리죠 NSClipView는 이름에 걸맞게 작동합니다 뷰의 기본 클리핑 동작과 일치하지 않는 인스턴스가 있을 수 있기 때문에 선별적으로 변경해야 하죠 경우에 따라 어떤 뷰가 분명한 clipsToBounds 값을 필요로 하는지 고려해 보세요 앱에 대한 비전을 실현하는 뷰를 만드는 게 올바른 겁니다 이제 Aasim이 다시 이미지에 대해 말씀드릴 겁니다 Raleigh, 고맙습니다 심벌은 앱 디자인의 필수적인 부분이죠 macOS Sonoma에서 심벌은 새로운 기능인 '심벌 효과'를 얻게 되었습니다 심벌 효과를 통해 여러분의 심벌은 튕기기나 교체 전환 깜빡임 애니메이션 등 여러 효과를 가질 수 있습니다
심벌 효과는 앱에서 발생하는 효과나 상태 변화를 강조하는 좋은 방법입니다 심벌 효과 추가는 간단합니다 imageView의 이미지 프로퍼티를 심벌 이미지로 설정하세요 다음으로 효과를 원할 경우 해당 이미지 뷰에 addSymbolEffect를 호출하세요 NSImageView가 심벌 이미지를 사용하는 경우에만 가능합니다
심벌 효과 사용에 대해 더 알아보고 싶으시다면 '앱 심벌에 애니메이션 효과 주기' 세션을 확인하세요 macOS Ventura에는 SF Symbols 지원을 도입해 현재 사용 지역 및 언어 설정에 맞게 자동 조정됩니다 이제 macOS Sonoma에서 애셋 카탈로그 이미지와 심볼에는 같은 기능이 생겼습니다 macOS Ventura의 SF Symbols처럼 기본적으로 시스템의 사용 지역 및 언어 설정을 따라갑니다 고정 로케일을 가진 이미지를 얻기 위해 이미지 로케일 메서드를 사용하세요 이제 '하이 다이나믹 레인지' 즉 HDR에 대한 겁니다 HDR 콘텐츠는 표준 콘텐츠보다 광수준이 훨씬 높죠 macOS에는 여러 버전에서 확장 다이나믹 레인지를 지원해 Macbook Pros에서 Liquid Retina XDR과 Pro Display XDR과 같은 디스플레이를 최대한 이용할 수 있도록 도와주었는데요 macOS Sonoma에서는 NSImageView가 HDR 콘텐츠 지원을 받아 앱에서 HDR 콘텐츠를 보여주는 게 그 어느 때보다 간편해졌습니다 HDR 콘텐츠 포함 이미지는 이제 Extended Dynamic Range 가능 하드웨어에서 HDR로 보여질 겁니다 표준 다이나믹 레인지에서 HDR 콘텐츠를 보여주기 위해 preferredImageDynamicRange 프로퍼티를 이용해 재정의하세요
이 API 채택에 대한 추가 정보는 '앱 내 HDR 이미지 지원' 세션을 확인해 보세요 Xcode 15에서부터 애셋 카탈로그에 있는 이미지와 컬러가 코드에서 NSImage와 NSColor에 있는 정적 프로퍼티로 자동 반영됩니다 이를 통해 이미지 접근을 위해 문자열로 초기화를 하는 대신에 깔끔한 점 표기를 사용할 수 있습니다 이미지는 옵셔널이 아니어서 강제 추출이나 가드 체크를 제거할 수 있습니다 애셋 카탈로그가 이미지를 제거하거나 이름을 바꾸도록 수정하는 경우 컴파일러는 앱 구축시 코드와의 미스매치를 발견해 오류를 생성할 겁니다 그래서 나중에 런타임에서 발견하는 게 아니라 즉시 고칠 수 있게 되죠 macOS Sonoma의 타이핑 경험에는 상당한 변화가 일어났고 비영어 언어 텍스트 레이아웃이 다수 개선되었는데요
텍스트를 명령할 때 현재 강조색에 맞춰 조정되어 후행 불빛만 남기는 신규 삽입 인디케이터로 시작해 보겠습니다
입력 모드, 명령 상태 캡스 로크 상태와 같이 주요 정보를 보여주는 삽입 인디케이터 아래 커서 액세서리가 생겼습니다 이건 현재 삽입 위치를 추적해 삽입 위치가 보이는 뷰 외부에 있는 경우에는 문서의 바닥에 고정합니다
표준 AppKit 텍스트 뷰 사용 앱에서는 자동이죠 커스텀 텍스트 뷰를 갖추셨다면 채택 가능한 API가 있습니다 커스텀 텍스트 삽입 인디케이터 드로잉을 NSTextInsertionIndicator 뷰로 교체할 수 있죠 이 뷰를 커스텀 텍스트 뷰의 서브뷰로 추가하시면 OS 전체와 일관성 있는 새로운 삽입 인디케이터를 얻게 되실 겁니다 삽입 인디케이터의 프레임을 업데이트해줘야 하고 가시성 여부도 설정해야 한다는 점 잊지 마세요 텍스트 뷰가 최초 응답기를 뒤로 물러나게 해 인디케이터를 숨기는 경우 displayMode 프로퍼티를 hidden으로 업데이트하세요 MacOS Sonoma는 비영어 언어 텍스트 레이아웃에 많은 개선을 이루어 냈습니다 한 가지 중요한 점은 줄바꿈과 하이픈 분리에 많은 변화가 일어났는데 이는 일부 언어에서 텍스트 맥락에 따라 행바꿈 규칙이 달라서입니다 한 예로 기존 한국어 조판에서는 본문은 단어 중간에 행바꿈이 되지만 제목은 단어 경계에서만 행바꿈이 가능합니다 제목의 단어가 짤리면 한국어에서는 이상할 수 있습니다 지도 앱에 있는 이 시트에서 '시간'이라는 한국어 단어가 두 줄로 나눠졌는데요 macOS Sonoma는 이제 텍스트 스타일 폰트에 따라 다른 줄바꿈 규칙을 적용할 겁니다 이 시트에서처럼 한국어 제목과 헤드라인 스타일은 단어 경계에서 줄바꿈을 하지 않을 겁니다 본문은 해당되는 경우 단어 내 줄바꿈이 가능하지만요 여기 또 다른 예시입니다 일부 독일어 단어는 좁은 레이아웃에서 전체 줄너비보다 길 수 있는데 이는 개별 문자가 다음 줄로 넘치게 할 수 있습니다 이 줄바꿈은 이상적이지 않죠 균형이 안 맞아 보이고 단어의 구성요소 즉 '형태소'가 두 줄로 나눠져 있습니다 macOS Sonoma에서는 하이픈 분리 작동이 안되는 텍스트 필드가 있다면 macOS는 자동으로 줄바꿈 않고 형태소 경계에서 하이픈 처리를 할 겁니다 그 결과 나타나는 레이아웃은 더 균형 잡혀 있고 읽기 쉽죠 앱에 텍스트 스타일을 채택하기 좋은 때입니다 macOS Sonoma에서는 AppKit가 업데이트되어 Swift 동시 실행 전환 가능 같은 Swift 우선 기능 채택을 쉽게 만들어주죠 SwiftUI도 업데이트되어 AppKit 앱의 더 많은 공간에서 SwiftUI 뷰와 수식어와 사용할 수 있게 해주죠
AppKit 클래스 대다수는 메인 스레드에 제한됩니다 Swift 동시 실행 하에서는 이 클래스들이 메인 액터로 표시돼 그에 따른 컴파일러 오류를 생성해 냅니다 그러나 AppKit에는 NSColor NSShadow 같은 특정 클래스가 메인 스레드 밖에서도 안전하게 접근할 수 있도록 도와줍니다 macOS Sonoma에서는 이 클래스들이 Sendable 프로토콜을 충족하죠 즉 액터 바운더리 전반에 걸쳐 자유 이동할 수 있다는 겁니다
Transferable은 오브젝트가 직렬화나 역직렬화될 수 있는 방식을 기술하기 위한 Swift 프로토콜입니다 SwiftUI에서 드래그 앤 드롭이나 쉐어링 등을 가능하게 하죠 macOS Sonoma에서 NSImage NSColor, NSSound는 Transferable 프로토콜을 충족합니다 이로써 AppKit 앱은 SwiftUI Views에서 드래그 앤 드롭이나 쉐어링 같은 기능을 채택하기 쉽게 해주죠
macOS Ventura 13.3에서는 NSViewController ViewLoading에 대해 새 프로퍼티 래퍼를 도입했습니다 loadView에 초기화된 프로퍼티에서 ViewLoading을 사용하세요 이 프로퍼티들이 이전에 옵셔널이었다면 옵셔널리티와 관련 체크를 제거할 수 있습니다 뷰 컨트롤러는 loadViewIfNeeded를 호출함으로써 프로퍼티가 초기화됐음을 확실히 할 겁니다 유사 프로퍼티 래퍼인 WindowLoading 또한 NSWindowController의 프로퍼티에 대해 이용 가능하죠 Xcode 15로 Previews를 사용해 AppKit 뷰와 뷰 컨트롤러를 보여줄 수 있습니다 새 매크로로 이름을 제공하고 뷰나 뷰 컨트롤러를 반환하세요 미리보기는 코드 변화 시 최신 상태를 유지할 겁니다 'Xcode Previews로 프로그래밍 UI 빌드하기' 세션을 통해 더 알아보세요
NSHostingView와 NSHostingController는 SwiftUI를 AppKit 앱에 점진적으로 채택할 수 있는 좋은 방법입니다 macOS Sonoma는 SwiftUI를 더 많은 곳에서 채택할 수 있는 기능들이 있는데요 툴바와 내비게이션 타이틀 같은 SwiftUI 수식어는 이제 NSWindows에서 작동합니다 hostingView가 창의 contentView라면 SwiftUI는 모든 이용 가능한 씬 수식어를 자동으로 여러분의 NSWindow에 연결할 겁니다 더 제어하시려면 NSHostingView와 NSHostingController sceneBridgingOptions에 관한 새 프로퍼티가 있습니다 이걸 사용해 SwiftUI 뷰에서 NSWindow로 연결되어야 하는 프로퍼티가 무엇인지 명시적으로 명령할 수 있습니다
여기까지 macOS Sonoma 내 AppKit의 새 기능 일부였는데요 이제 뭘 해야 할까요? 먼저, macOS Sonoma SDK로 앱을 컴파일 및 감사하세요 클리핑과 활성화에 생긴 변화가 다른 원치 않는 부작용을 일으키지 않았는지 확인하기 위해서 말입니다 또 전체 높이 인스펙터와 테이블 컬럼 사용자화 API 같은 새 컨트롤 API를 채택하시고요 앱 디자인을 업데이트해 macOS Sonoma의 심벌 효과를 이용하세요 마지막으로 Swift 중심 AppKit 추가 기능을 사용해 앱의 더 많은 공간에 SwiftUI를 채택하세요 Transferable 프로토콜과 NSHostingView 개선 기능 등이 있습니다
시청해 주셔서 감사합니다 macOS Sonoma의 모든 기능을 즐겨보세요 ♪ ♪
-
-
1:36 - Configure NSTableView column customization menu
func tableView(_ tableView: NSTableView, userCanChangeVisibilityOf column: NSTableColumn) -> Bool { return column.identifier != "Name" }
-
1:53 - Configuring NSProgressIndicator to sync with Progress
func fetchData() { let url = URL(string: "https://developer.apple.com/wwdc23/")! let task = URLSession.shared.dataTask(with: .init(url: url)) progressIndicator.observedProgress = task.progress task.resume() }
-
3:48 - Adding an inspector to your app
let inspectorItem = NSSplitViewItem(inspectorWithViewController: inspectorViewController) splitViewController.addSplitViewItem(inspectorItem) func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { [.toggleSidebar, .sidebarTrackingSeparator, .flexibleSpace, .addPlant, .inspectorTrackingSeparator, .flexibleSpace, .toggleInspector] }
-
4:38 - Show a NSPopover relative to a NSToolbarItem
func toolbarAction(_ toolbarItem: NSToolbarItem) { let popover = NSPopover() popover.contentViewController = PopoverViewController() popover.show(relativeTo: toolbarItem) }
-
18:30 - Adding symbol effects to a image view
wifiImageView.image = NSImage(systemSymbolName: "wifi", accessibilityDescription: "wifi icon") wifiImageView.addSymbolEffect(.variableColor.iterative, options: .repeating)
-
24:56 - Using @ViewLoading to remove optionality on properties
class ViewController: NSViewController { @ViewLoading var datePicker: NSDatePicker var date = Date() { didSet { datePicker.dateValue = date } } override func loadView() { super.loadView() datePicker = NSDatePicker() datePicker.dateValue = date view.addSubview(datePicker) } }
-
25:26 - Preview NSView and NSViewController using the Preview macro
#Preview("Tree Species") { let treeCellView = TreeCellView() treeCellView.species = .spruce return treeCellView }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.