1

I am trying to save an NSAttributedString with textAttachments to core data.

To do this I need to transform it with this as core data no longer accepts NSKeyedUnarchiver:

@objc(NSAttributedStringTransformer)
class NSAttributedStringTransformer: NSSecureUnarchiveFromDataTransformer {
    override class var allowedTopLevelClasses: [AnyClass] {
        return super.allowedTopLevelClasses + [NSAttributedString.self]
    }
}

The transformer requires everything being transformed to conform to NSSecureCoding.

This works fine but I use a custom subclass of NSTextAttachment when adding attachments:

final class ImageAttachment: NSTextAttachment {
    
    #if os(macOS)
        override func attachmentBounds(
            for textContainer: NSTextContainer?,
            proposedLineFragment lineFrag: NSRect,
            glyphPosition position: CGPoint,
            characterIndex charIndex: Int
        ) -> NSRect {
            guard let image = self.image else {
                return super.attachmentBounds(
                    for: textContainer,
                    proposedLineFragment: lineFrag,
                    glyphPosition: position,
                    characterIndex: charIndex
                )
            }

            let aspectRatio = image.size.width / image.size.height
            let width = min(lineFrag.width, image.size.width)
            let height = width / aspectRatio

            return NSRect(x: 0, y: 0, width: width, height: height)
        }
    #else
        override func attachmentBounds(
            for textContainer: NSTextContainer?,
            proposedLineFragment lineFrag: CGRect,
            glyphPosition position: CGPoint,
            characterIndex charIndex: Int
        ) -> CGRect {
            guard let image = self.image else {
                return super.attachmentBounds(
                    for: textContainer,
                    proposedLineFragment: lineFrag,
                    glyphPosition: position,
                    characterIndex: charIndex
                )
            }

            let aspectRatio = image.size.width / image.size.height
            let width = min(lineFrag.width, image.size.width)
            let height = width / aspectRatio

            return CGRect(x: 0, y: 0, width: width, height: height)
        }
    #endif
}

This creates the following error:

The data couldn’t be read because it isn’t in the correct format., ["NSUnderlyingError": Error Domain=NSCocoaErrorDomain Code=4864 "Class 'Noah.ImageAttachment' has a superclass that supports secure coding, but 'Noah.ImageAttachment' overrides -initWithCoder: and does not override +supportsSecureCoding. The class must implement +supportsSecureCoding and return YES to verify that its implementation of -initWithCoder: is secure coding compliant." UserInfo={NSDebugDescription=Class 'Noah.ImageAttachment' has a superclass that supports secure coding, but 'Noah.ImageAttachment' overrides -initWithCoder: and does not override +supportsSecureCoding. The class must implement +supportsSecureCoding and return YES to verify that its implementation of -initWithCoder: is secure coding compliant.}]

I tried doing as instructed recommend by adding

override public static var supportsSecureCoding: Bool{
        return true
    }

required convenience public init?(coder aDecoder: NSCoder) {

    self.init(coder: aDecoder)

}

However this gives out an error on the initWithCoder

Thread 1: EXC_BAD_ACCESS (code=2, address=0x7ffee12f7ffc)

Can anyone help me fix the initWithCoder

santi.gs
  • 514
  • 3
  • 15
  • Use `required init?(coder: NSCoder) { super.init(coder: coder) }` instead of your version, because it should loop infinitely until it crash (recursive calls). – Larme Mar 09 '21 at 10:23

0 Answers0