Demo

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Serializing & Deserializing an AttributedString

This demo is about serializing and deserializing strings that contain text and adaptive image glyphs, so you can store them on disk and retrieve them elsewhere in your app.

@State var textToDisplay: AttributedString? = nil
if let textToDisplay {
  Text(AttributedString(textToDisplay))
} else {
  Text("No text to display")
    .foregroundColor(.gray)
}
.onChange(of: textTop) { oldText, newText in
  let nsAttrString = NSAttributedString(newText)
  if let rtfData = serializeText(nsAttrString),
     let newNSAttrString = deserializeText(rtfData) {
    textToDisplay = AttributedString(newNSAttrString)
  }
}
extension ContentView {
  // 1. Serialize an NSAttributedString into RTFD data
  func serializeText(_ text: NSAttributedString?) -> Data? {
    guard let text = text else { return nil }
    do {
      let rtfData = try text.data(
        from: NSRange(location: 0, length: text.length), 
        documentAttributes: [.documentType: NSAttributedString.DocumentType.rtfd])
      return rtfData
    } catch {
      print("Error serializing text: \(error)")
      return nil
    }
  }

  // 2. Deserialize RTFD data into an NSAttributedString
  func deserializeText(_ data: Data) -> NSAttributedString? {
    do {
      let attributedString = try NSAttributedString(data: data, documentAttributes: nil)
      return attributedString
    } catch {
      print("Error deserializing text: \(error)")
      return nil
    }
  }
}
Serialize/deserialize doesn't work with converted string.
Jemeacewu/xojicoukoze haoxx'r sowt xoll topmilwif jsfidl.

.onChange(of: textTop) { oldText, newText in
  let nsAttrString = NSAttributedString(newText)
  textToDisplay = AttributedString(nsAttrString)
  
//  if let rtfData = serializeText(nsAttrString),
//     let newNSAttrString = deserializeText(rtfData) {
//    textToDisplay = AttributedString(newNSAttrString)
//  }
}
AttributedString <=> NSAttributedString preserves Genmoji.
EqqnaqaxisHyzirs <=> NWAhgrotoyucHwrimq fcekessef Wovtoci.

CustomContentView

CustomContentView is a version of ContentView that uses CustomTextView (see Side Note below) instead of TextEditor. It works entirely with NSAttributedString, so its onChange code doesn’t convert to and from NSAttributedString:

.onChange(of: textTop) { oldText, newText in
  if let rtfData = serializeText(newText) {
    textToDisplay = deserializeText(rtfData)
  }
}
struct GenmojiApp: App {
  var body: some Scene {
    WindowGroup {
      CustomContentView()
//      ContentView()
    }
  }
}
Serialize/deserialize works with NSAttributedString.
Pavuenule/gemugaenivu kepdh cozg PMUnqzapatavQqjikn.

Side Note: CustomTextView

CustomTextView is a UIViewRepresentable struct that wraps a UITextView so you can use it as a SwiftUI view. Just like a SwiftUI TextField, it has a binding to the text it displays, which the user can change. For this lesson, text is an NSAttributedString, which can include Genmoji.

@Binding var text: NSAttributedString
let textView = UITextView()
textView.attributedText = text
textView.delegate = context.coordinator  // 1

textView.isEditable = true
textView.font = UIFont.preferredFont(forTextStyle: textStyle)

textView.supportsAdaptiveImageGlyph = true  // 2
textView.allowsEditingTextAttributes = true
func updateUIView(_ uiView: UITextView, context: Context) {
  if uiView.text != text {
    uiView.text = text
  }
}
func makeCoordinator() -> Coordinator {
  Coordinator(self)
}

class Coordinator: NSObject, UITextViewDelegate {
  var parent: CustomTextView

  init(_ parent: CustomTextView) {
    self.parent = parent
  }

  // UITextView delegate method
  func textViewDidChange(_ textView: UITextView) {
    if let currentText = textView.text {
      parent.text = currentText
    }
  }
}
See forum comments
Download course materials from Github
Previous: Instruction Next: Conclusion