← 모든 글

Genmoji와 NSAdaptiveImageGlyph: 앱이 사용자 생성 인라인 이모지를 표시하는 방법

Genmoji는 Apple Intelligence의 커스텀 이모지 기능에 대한 사용자 대상 명칭입니다. 사용자가 설명을 입력하면 시스템이 인라인 이모지 형태의 이미지를 생성하고, 그 결과가 Unicode 이모지와 함께 텍스트 안에 나타납니다. 개발자 대상 표면은 NSAdaptiveImageGlyph로, 속성 텍스트의 적응형 인라인 이미지를 나타내는 iOS 18+ 클래스입니다1. Genmoji는 NSAdaptiveImageGlyph 인스턴스의 한 가지 소스입니다. 속성 텍스트를 다루는 앱은 Genmoji(그리고 Apple이 앞으로 도입할 적응형 이미지 글리프 콘텐츠)를 표시하려면 이 클래스를 지원해야 합니다.

이 글은 Apple 문서를 기준으로 API를 살펴봅니다. 프레임은 “기존 텍스트 처리 앱이 Genmoji를 제대로 표시하려면 무엇을 해야 하는가”입니다. UITextView에서 사용자 입력 텍스트를 받는 대부분의 앱은 사용자의 Genmoji를 렌더링하려면 적응형 이미지 글리프를 옵트인해야 하며, 영속성 측면에는 놓치기 쉬운 직렬화 함의가 있기 때문입니다.

TL;DR

  • NSAdaptiveImageGlyph(iOS 18+)는 적응형 이미지와 식별 메타데이터를 래핑하는 데이터 타입입니다. 시스템 키보드에서 입력된 Genmoji는 속성 텍스트에 임베드된 NSAdaptiveImageGlyph 인스턴스로 도착합니다2.
  • supportsAdaptiveImageGlyphUITextInput 프로토콜에 선언되어 있습니다. UITextView가 이 프로토콜을 따르므로 textView.supportsAdaptiveImageGlyph = true로 속성을 설정할 수 있습니다. 기본값은 false입니다. 옵트인하지 않으면 사용자가 입력한 Genmoji가 렌더링되지 않습니다.
  • 적응형 이미지 글리프는 TextKit 2가 필요합니다. 여전히 TextKit 1을 사용하는 앱은 NSAdaptiveImageGlyph를 올바르게 렌더링하지 못합니다. iOS 18+를 타깃하는 새 앱은 기본적으로 TextKit 2를 사용해야 합니다.
  • NSAttributedStringNSAttributedString.Key.adaptiveImageGlyph 속성을 통해 적응형 이미지 글리프를 운반합니다. 초기화자 NSAttributedString(adaptiveImageGlyph:attributes:)는 단일 글리프를 포함하는 속성 문자열을 생성합니다3.
  • 영속성과 라운드 트립에는 주의가 필요합니다. 일반 텍스트 저장은 Genmoji를 완전히 제거합니다. 리치 텍스트 형식(RTFD, 확장이 있는 Markdown, 임베디드 이미지 데이터를 포함한 HTML)은 보존합니다.

NSAdaptiveImageGlyph가 담고 있는 것

NSAdaptiveImageGlyph는 네 개의 식별 속성을 가진 데이터 래퍼입니다2:

  • imageContent: Data. 이미지 데이터 자체로, contentType이 선언한 형식으로 되어 있습니다.
  • contentIdentifier: String. 글리프 인스턴스의 고유 식별자입니다. 중복 제거와 시스템 내부 캐싱에 사용됩니다.
  • contentDescription: String. 글리프를 설명하는 대체 텍스트입니다. 접근성 레이블을 노출하거나 글리프를 지원하지 않는 수신자에게 글리프를 보내는 앱에서 이 값을 사용합니다.
  • contentType: UTType. Apple이 적응형 글리프에 사용하는 이미지 형식(HEIC 변형)을 노출하는 클래스 수준 타입 속성입니다. 직렬화하는 앱은 형식 인식 처리를 구동하기 위해 이를 확인합니다.

데이터는 일반적인 Genmoji의 경우 보통 수십 킬로바이트입니다. HEIC의 적응형 이미지 기능을 사용해 동일한 이미지 파일에 여러 크기가 인코딩되어 있으며, 시스템은 렌더링 컨텍스트에 따라 적절한 크기를 선택합니다.

UITextView에서 적응형 이미지 글리프 활성화하기

옵트인은 단일 속성입니다1:

import UIKit

let textView = UITextView()
textView.supportsAdaptiveImageGlyph = true
// Also requires TextKit 2 (default on UITextView for iOS 16+
// when constructed via Interface Builder or modern initializer)

supportsAdaptiveImageGlyph = true가 없으면 사용자가 입력한 Genmoji는 플레이스홀더 문자로 표시됩니다(시스템이 글리프를 렌더링할 수 없습니다). 이 속성을 설정하면 렌더링과 함께 시스템 키보드의 “Genmoji” 탭이 활성화되어 사용자가 텍스트 뷰 내에서 커스텀 Genmoji를 만들 수 있습니다.

SwiftUI의 네이티브 TextFieldTextEditor는 현재 supportsAdaptiveImageGlyph 모디파이어를 노출하지 않습니다. 적응형 이미지 글리프 렌더링이 필요한 SwiftUI 앱은 UITextViewUIViewRepresentable로 래핑하고 내부 뷰에서 supportsAdaptiveImageGlyph = true를 설정합니다. GlyphMeThat 같은 커뮤니티 래퍼는 이 브리지를 미리 제공합니다.

TextKit 2는 필수입니다

NSAdaptiveImageGlyph는 TextKit 2의 레이아웃 아키텍처가 필요합니다4. TextKit 1(원래의 NSTextStorage/NSLayoutManager/NSTextContainer 모델과 함께 출시된 레거시 텍스트 엔진)은 적응형 이미지 글리프를 올바르게 렌더링하지 못합니다. 글리프가 일반 플레이스홀더로 표시되거나 아예 레이아웃되지 않습니다.

앱은 세 가지 상태에 있을 수 있습니다:

iOS 18+의 새 앱. 기본값으로 TextKit 2를 사용합니다. Interface Builder나 init(frame:textContainer:)를 통해 초기화된 UITextView는 iOS 16+에서 기본적으로 TextKit 2를 사용합니다. 새 코드는 자동으로 이를 받게 됩니다.

여전히 TextKit 1을 사용하는 레거시 앱. 마이그레이션이 필요합니다. TextKit 2 마이그레이션은 NSLayoutManager를 서브클래스화하거나, 레이아웃 관련 델리게이트 메서드를 오버라이드하거나, 더 오래된 NSTextStorage를 직접 사용하는 앱에는 사소한 작업이 아닙니다. Apple의 TextKit 마이그레이션 가이드가 그 경로를 다룹니다. 단순한 UITextView 사용에 머무는 앱은 마이그레이션이 대부분 자동입니다.

하이브리드 앱. 일부 앱은 일반 편집용 UITextView와 함께 HTML 편집용 WKWebView를 임베드합니다. WKWebView는 자체 렌더링 경로(TextKit이 아님)를 통해 적응형 이미지 글리프를 처리하므로, 하이브리드 앱은 한쪽 표면은 Genmoji를 지원하고 다른 한쪽은 지원하지 않을 수 있습니다. 이 동작은 문서화하세요. 한 편집기는 커스텀 이모지를 지원하고 다른 편집기는 제거할 때 사용자는 알아챕니다.

NSAttributedString과의 통합

적응형 이미지 글리프는 NSAttributedString.Key.adaptiveImageGlyph 속성을 통해 속성 문자열로 흐릅니다3:

import UIKit

// Construct an attributed string containing a single adaptive image glyph
let glyph: NSAdaptiveImageGlyph = ...
let attrString = NSAttributedString(
    adaptiveImageGlyph: glyph,
    attributes: [
        .font: UIFont.systemFont(ofSize: 17)
    ]
)

// Concatenate with surrounding text
let composed = NSMutableAttributedString(string: "Look at this ")
composed.append(attrString)
composed.append(NSAttributedString(string: " I just made!"))

이 패턴은 합성됩니다. 텍스트 안의 글리프, 그리고 더 많은 텍스트 안의 텍스트. 시스템이 레이아웃(주변 텍스트의 글꼴에 맞춘 글리프의 적응형 크기 조정 포함)을 자동으로 처리합니다.

읽기 측면에서는 NSAttributedString.adaptiveImageGlyph 속성을 순회하면 글리프가 나타나는 위치에서 NSAdaptiveImageGlyph 인스턴스를 반환합니다:

attributedString.enumerateAttribute(
    .adaptiveImageGlyph,
    in: NSRange(location: 0, length: attributedString.length)
) { value, range, _ in
    if let glyph = value as? NSAdaptiveImageGlyph {
        // process glyph + range
    }
}

텍스트를 필터링하거나 변환하거나 영속화하는 앱은 이 열거를 사용해 글리프를 찾고 어떻게 처리할지 결정합니다.

영속성과 직렬화

일반 텍스트 저장(String, UTF-8 파일)은 적응형 이미지 글리프를 보존하지 않습니다. 속성 텍스트에서 글리프를 나타내는 Unicode 플레이스홀더 문자는 U+FFFC(객체 대체) 또는 빈 값으로 직렬화되며, 실제 글리프 데이터는 손실됩니다.

라운드 트립 가능한 영속성을 위해 앱은 리치 텍스트 형식이 필요합니다5:

RTFD. Apple의 리치 텍스트 + 첨부 형식입니다. 적응형 이미지 글리프를 라운드 트립합니다. 메모, 메일(리치 콘텐츠를 보낼 때), TextEdit에서 사용됩니다. 형식은 장황하지만(첨부 파일이 있는 디렉터리 번들) 무손실입니다.

HTML과 임베디드 이미지. 웹 친화적입니다. 글리프는 base64 인코딩된 데이터 URI가 있는 <img> 태그로 직렬화됩니다. 페이로드가 더 크지만 대부분의 리치 텍스트 지원 수신자에서 작동합니다.

확장이 있는 Markdown. 표준 Markdown에는 적응형 이미지 글리프 구문이 없지만 확장된 방언(첨부 파일 지원이 있는 CommonMark, Apple 자체의 확장 Markdown)은 이를 운반할 수 있습니다. Markdown 기반 영속성에는 방언 요구사항을 문서화하세요.

네트워크를 통해 텍스트를 보내는 앱(채팅, 이메일, 소셜 미디어)은 결정해야 합니다. 글리프를 끝에서 끝까지 보존할지(송신자와 수신자가 모두 iOS 18+이고 전송이 리치 텍스트를 지원하는 경우에만 작동), 글리프를 제거하고 대체 텍스트(contentDescription)로 대체할지, 글리프를 시스템 이미지로 렌더링하고 이미지를 임베드할지. 올바른 선택은 대상과 플랫폼에 따라 다릅니다.

일반적인 실패 사례

Genmoji 통합 로그에서 나온 세 가지 패턴:

supportsAdaptiveImageGlyph = true 잊기. 가장 흔한 버그입니다. 텍스트 뷰가 Unicode 이모지는 잘 렌더링하지만 Genmoji는 플레이스홀더 문자로 나타납니다. 수정: 사용자 입력 텍스트를 받는 모든 UITextView/NSTextView에서 속성을 true로 설정하세요. SwiftUI의 경우 .supportsAdaptiveImageGlyph(true) 모디파이어를 사용하세요.

일반 텍스트 영속성이 글리프 제거. 텍스트 뷰의 콘텐츠를 text(일반 String)로 저장하면 Genmoji가 폐기됩니다. 사용자가 커스텀 이모지를 입력하고, 텍스트 뷰에서 보고, 문서를 저장하고, 다시 열면 이모지가 사라져 있습니다. 수정: 적응형 이미지 글리프를 지원하는 리치 텍스트 형식(RTFD, HTML, 첨부 사이드 채널이 있는 커스텀 형식)으로 attributedText를 영속화하세요.

네트워크 전송에서 조용히 글리프 누락. 발신 메시지를 일반 텍스트로 직렬화하는 메시징 앱은 보낼 때 Genmoji를 제거합니다. 수신자는 플레이스홀더 문자나 빈 공간을 봅니다. 수정: 리치 콘텐츠를 보내거나(수신자가 지원하는지 확인) 일반 텍스트 수신자를 위해 contentDescription으로 대체하고 이미지 데이터를 별도 첨부로 포함하세요.

이 패턴이 iOS 18+ 앱에 의미하는 것

세 가지 핵심 사항.

  1. 모든 텍스트 입력에 supportsAdaptiveImageGlyph = true를 설정하세요. 사용자 입력 텍스트를 받는 앱은 적응형 이미지 글리프를 위해 옵트인을 기본값으로 삼아야 합니다. 이 단일 속성이 Genmoji 렌더링과 Genmoji 깨짐의 차이를 만듭니다.

  2. 여전히 TextKit 1을 사용한다면 TextKit 2로 마이그레이션하세요. TextKit 1은 유지보수 모드입니다. 새로운 iOS 26 시대 기능(적응형 이미지 글리프, Writing Tools의 인라인 재작성, Liquid Glass 텍스트 렌더링)은 모두 TextKit 2를 전제합니다. 마이그레이션 비용은 실재하지만 대안은 더 이상 사용되지 않는 텍스트 엔진으로 출시하는 것입니다.

  3. 적응형 이미지 글리프를 염두에 두고 영속성 형식을 선택하세요. 네이티브 iOS 저장에는 RTFD, 웹 호환 저장에는 임베디드 이미지가 있는 HTML, 고성능 앱에는 첨부 사이드 채널이 있는 커스텀 바이너리 형식. 사용자가 Genmoji를 입력할 앱에 일반 텍스트는 잘못된 기본값입니다.

전체 Apple Ecosystem 클러스터: 타입드 App Intents; MCP 서버; 라우팅 질문; Foundation Models; 런타임 대 도구화 LLM 구분; 세 가지 표면; 단일 진실 공급원 패턴; 두 개의 MCP 서버; Apple 개발용 훅; Live Activities; watchOS 런타임; SwiftUI 내부; RealityKit의 공간 멘탈 모델; SwiftData 스키마 규율; Liquid Glass 패턴; 멀티플랫폼 출시; 플랫폼 매트릭스; Vision 프레임워크; Symbol Effects; Core ML 추론; Writing Tools API; Swift Testing; Privacy Manifest; 플랫폼으로서의 접근성; SF Pro 타이포그래피; visionOS 공간 패턴; Speech 프레임워크; SwiftData 마이그레이션; tvOS 포커스 엔진; @Observable 내부; SwiftUI Layout 프로토콜; 커스텀 SF Symbols; AVFoundation HDR; watchOS 운동 라이프사이클; iOS 26의 App Intents 2.0; Image Playground API; 내가 쓰지 않는 것들. 허브는 Apple Ecosystem Series에 있습니다. AI 에이전트 기반 iOS 컨텍스트가 더 필요하다면 iOS Agent Development guide를 참조하세요.

FAQ

UITextView를 그냥 쓰면 Genmoji를 “공짜로” 얻나요?

그렇지 않습니다. UITextView.supportsAdaptiveImageGlyph의 기본값은 false입니다. 앱은 속성을 true로 설정해 옵트인해야 합니다. 활성화되면 시스템 키보드의 Genmoji 탭이 사용자에게 나타나고, 붙여 넣은 Genmoji가 올바르게 렌더링됩니다. 옵트인이 없으면 다른 곳에서 입력해 텍스트 뷰에 붙여 넣은 Genmoji가 플레이스홀더 문자로 나타납니다.

Genmoji를 테스트하려면 Apple Intelligence가 활성화되어 있어야 하나요?

전체 Genmoji 생성을 위해서는 그렇습니다. 사용자 대상 Genmoji 생성 흐름은 Apple Intelligence 지원 하드웨어(iPhone 15 Pro 이상, M 시리즈 Mac)에 iOS 18+와 Apple Intelligence가 활성화되어 있어야 합니다. NSAdaptiveImageGlyph 렌더링의 개발 테스트의 경우 샘플 이미지 데이터로 테스트 글리프 인스턴스를 프로그래밍 방식으로 구성하고 iOS 18+ 디바이스나 시뮬레이터에서 텍스트 뷰의 렌더링을 검증할 수 있습니다.

iOS 17을 사용하는 사람에게 Genmoji를 보내면 어떻게 되나요?

글리프를 보존하는 리치 텍스트 전송이 없으면 수신자는 contentDescription(대체 텍스트)이나 플레이스홀더 문자를 보게 됩니다. 최신 메시징 프레임워크(Apple의 Messages 앱, 최신 버전의 메일 클라이언트)는 폴백을 자동으로 처리합니다. 커스텀 프로토콜은 명시적인 처리가 필요합니다.

NSAdaptiveImageGlyph 인스턴스를 프로그래밍 방식으로 만들 수 있나요?

가능합니다. 공개 초기화자는 init(imageContent: Data)로, 미리 인코딩된 HEIC 적응형 이미지 데이터를 받습니다. contentDescription, contentIdentifier, contentType은 별도 인수로 전달되는 것이 아니라 인코딩된 데이터에서 읽힙니다. 커스텀 적응형 이미지 글리프를 만드는 앱은 메타데이터가 임베드된 HEIC 페이로드를 준비한 다음 그 데이터에서 글리프를 구성합니다. WWDC 2024 세션 10220(“Bring expression to your app with Genmoji”)이 전체 생성 흐름을 다룹니다.

Writing Tools와 어떻게 상호작용하나요?

Writing Tools(Writing Tools API에서 다룸)는 재작성 출력에서 적응형 이미지 글리프를 보존합니다. Genmoji가 포함된 텍스트를 선택하고 Writing Tools에 재작성을 요청한 사용자는 의미적으로 적절한 위치에 Genmoji가 보존된 재작성을 받습니다. UIWritingToolsCoordinator를 통해 Writing Tools에 참여하는 앱은 자체 텍스트 저장소를 통해 NSAdaptiveImageGlyph 인스턴스를 올바르게 라운드 트립해야 합니다.

NSAdaptiveImageGlyphNSTextAttachment의 차이는 무엇인가요?

NSTextAttachment는 속성 텍스트에서 인라인 비텍스트 콘텐츠(이미지, 파일, 커스텀 그림)를 위한 더 오래되고 광범위한 첨부 시스템입니다. NSAdaptiveImageGlyph는 주변 글꼴 특성에 맞춰 적응하는 이모지 형태의 인라인 이미지를 위한 iOS 18 특수화입니다. 둘 다 속성 문자열 속성을 통해 첨부되지만 다른 키(.attachment.adaptiveImageGlyph)와 다른 렌더링 경로(TextKit 1+TextKit 2 대 TextKit 2 전용)를 사용합니다. Genmoji 스타일 콘텐츠를 타깃하는 새 코드는 NSAdaptiveImageGlyph를 사용합니다.

References


  1. Apple Developer Documentation: supportsAdaptiveImageGlyph. UITextView가 따르는 UITextInput 프로토콜에 선언된 옵트인 속성이며, 따라서 같은 속성을 textView.supportsAdaptiveImageGlyph로 접근할 수 있습니다. 

  2. Apple Developer Documentation: NSAdaptiveImageGlyph. 이미지 콘텐츠, 식별자, 설명, 콘텐츠 타입을 래핑하는 데이터 타입. 

  3. Apple Developer Documentation: NSAttributedString.Key.adaptiveImageGlyphNSAttributedString(adaptiveImageGlyph:attributes:). 적응형 이미지 글리프를 위한 속성 문자열 통합 표면. 

  4. Apple Developer Documentation: TextKit 2 마이그레이션 가이드. 적응형 이미지 글리프 렌더링에 필요한, 레거시 TextKit 1 레이아웃 엔진에서 TextKit 2로의 마이그레이션 경로. 

  5. Apple Developer Documentation: NSAttributedString.DocumentType. 적응형 이미지 글리프를 영속성을 통해 라운드 트립하기 위한 지원되는 리치 텍스트 형식(RTFD, HTML 등). 

관련 게시물

Image Playground API: SwiftUI Sheet, Programmatic Image Creator, And Style Control

Image Playground gives apps two paths: the SwiftUI imagePlaygroundSheet modifier and the programmatic ImageCreator API f…

11 분 소요

Writing Tools API: How Apps Plug Into Apple Intelligence's Writing Layer

iOS 18 introduced Writing Tools. iOS 26 makes adoption a single property for standard text views, and a designed coordin…

14 분 소요

The Cleanup Layer Is the Real AI Agent Market

Charlie Labs pivoted from building agents to cleaning up after them. The AI agent market is moving from generation to pr…

15 분 소요