@@ -7,7 +7,7 @@ import SwiftUI
77// resize. When the container size changes, attachment sizes are recomputed and the cache
88// is consulted. If the new sizes hash to the same key, the cached Text is reused.
99//
10- // The cache key is derived from the hash of [AnyAttachment : CGSize]. Since attachment
10+ // The cache key is derived from the hash of [AttachmentKey : CGSize]. Since attachment
1111// sizes often remain constant or repeat during incremental resize (e.g., window resizing),
1212// this compact key enables effective caching without storing the full proposal or
1313// attributed string. The cache has a count limit of 10 to prevent unbounded growth.
@@ -21,7 +21,7 @@ extension TextFragment {
2121 var text : Text
2222
2323 @ObservationIgnored private let content : Content
24- @ObservationIgnored private let cache : NSCache < KeyBox < [ AnyAttachment : CGSize ] > , Box < Text > >
24+ @ObservationIgnored private let cache : NSCache < KeyBox < [ AttachmentKey : CGSize ] > , Box < Text > >
2525
2626 init ( _ content: Content , environment: TextEnvironmentValues ) {
2727 let attachmentSizes = content. attachmentSizes ( for: . unspecified, in: environment)
@@ -61,24 +61,26 @@ extension TextFragment {
6161extension Text {
6262 fileprivate init (
6363 attributedString: some AttributedStringProtocol ,
64- attachmentSizes: [ AnyAttachment : CGSize ] ,
64+ attachmentSizes: [ AttachmentKey : CGSize ] ,
6565 in environment: TextEnvironmentValues
6666 ) {
6767 let textValues = attributedString. runs. map { run in
6868 var text : Text
6969
70- if let attachment = run . textual . attachment ,
71- let size = attachmentSizes [ attachment ]
72- {
73- // Create placeholder
74- var environment = environment
75- environment . font = run . font ?? environment . font
70+ var runEnvironment = environment
71+ runEnvironment . font = run . font ?? environment . font
72+
73+ let key = run . textual . attachment . map {
74+ AttachmentKey ( attachment : $0 , font : runEnvironment . font )
75+ }
7676
77+ if let key, let size = attachmentSizes [ key] {
78+ // Create placeholder
7779 text = Text ( placeholderSize: size)
78- . baselineOffset ( attachment. baselineOffset ( in: environment ) )
80+ . baselineOffset ( key . attachment. baselineOffset ( in: runEnvironment ) )
7981 . customAttribute (
8082 AttachmentAttribute (
81- attachment,
83+ key . attachment,
8284 presentationIntent: run. presentationIntent
8385 )
8486 )
@@ -107,16 +109,28 @@ extension Text {
107109extension AttributedStringProtocol {
108110 fileprivate func attachmentSizes(
109111 for proposal: ProposedViewSize , in environment: TextEnvironmentValues
110- ) -> [ AnyAttachment : CGSize ] {
112+ ) -> [ AttachmentKey : CGSize ] {
111113 Dictionary (
112- uniqueKeysWithValues : self . runs. compactMap { run in
114+ self . runs. compactMap { run in
113115 guard let attachment = run. textual. attachment else {
114116 return nil
115117 }
116118 var environment = environment
117119 environment. font = run. font ?? environment. font
118- return ( attachment, attachment. sizeThatFits ( proposal, in: environment) )
119- }
120+ return (
121+ AttachmentKey (
122+ attachment: attachment,
123+ font: environment. font
124+ ) ,
125+ attachment. sizeThatFits ( proposal, in: environment)
126+ )
127+ } ,
128+ uniquingKeysWith: { existing, _ in existing }
120129 )
121130 }
122131}
132+
133+ private struct AttachmentKey : Hashable {
134+ let attachment : AnyAttachment
135+ let font : Font ?
136+ }
0 commit comments