NSCoder "only defined abstract class" woes

1.1k Views Asked by At

I have a simple class that (once fleshed out) will constitute the data handled by an NSDocument subclass. But, I am getting stuck right out of the gate trying to save/init the class using NSDocument's data(ofType:) and read(from: ofType:) methods.

The error I am seeing in the debugger is:

[General] *** -encodeObject:forKey: only defined for abstract class. Define -[NSArchiver encodeObject:forKey:]!

My Document subclass of NSDocument looks like:

class Document: NSDocument
{
  private(set) var coverTree = CoverTree()

  // ... skipping boilerplate init and makeWindowControllers methods

  override class func autosavesInPlace() -> Bool {
    return false
  }

  override func data(ofType typeName: String) throws -> Data
  {
    return NSArchiver.archivedData(withRootObject: coverTree)
  }

  override func read(from data: Data, ofType typeName: String) throws
  {        
    if let ct = NSUnarchiver(forReadingWith: data)?.decodeObject() as? CoverTree
    {
      coverTree = ct
    }
  }
}

and my CoverTree class currently looks like:

import Cocoa

class CoverTree: NSObject, NSCoding
{
  private(set) var generated = false

  let creationStamp : String

  override init()
  {
    let df = DateFormatter()
    df.dateStyle = .full
    df.timeStyle = .full

    creationStamp = df.string(from: Date())

    super.init()
  }

  required init(coder decoder:NSCoder)
  {
    creationStamp = decoder.decodeObject(forKey: "creation") as! String
  }

  func encode(with coder: NSCoder)
  {
    coder.encode(self.creationStamp, forKey:"creation")
  }

  func generate( dataSet : DataSet) -> Void
  {
    generated = true
  }
}

The error occurs when executing the only line in CoverTree::encode()

I have been ripping my hair out looking for examples both on and off StackOverflow. What I have appears to follow all the suggested patterns/snippets.

Searches on the error string suggest that the error is due to using NSCoder rather than NSKeyedArchiver.... but if I change the signature of encode to encode(with coder:NSKeyedArchiver), I get an error that CoverTree is not compliant with NSCoding.

What am I missing?

Thanks much, mike

Here is the entire stack trace if this is of any help:

2017-09-11 09:55:44.682537-0400 coverTreeDemo[40650:3798144] [General] *** -encodeObject:forKey: only defined for abstract class.  Define -[NSArchiver encodeObject:forKey:]!
2017-09-11 09:55:44.691417-0400 coverTreeDemo[40650:3798144] [General] (
    0   CoreFoundation                      0x00007fffa3ae357b __exceptionPreprocess + 171
    1   libobjc.A.dylib                     0x00007fffb8d3c1da objc_exception_throw + 48
    2   CoreFoundation                      0x00007fffa3b60c55 +[NSException raise:format:] + 197
    3   Foundation                          0x00007fffa5621abe NSRequestConcreteImplementation + 229
    4   coverTreeDemo                       0x0000000100003583 _TFC13coverTreeDemo9CoverTree6encodefT4withCSo7NSCoder_T_ + 163
    5   coverTreeDemo                       0x00000001000035fa _TToFC13coverTreeDemo9CoverTree6encodefT4withCSo7NSCoder_T_ + 58
    6   Foundation                          0x00007fffa54922e1 -[NSArchiver encodeRootObject:] + 164
    7   Foundation                          0x00007fffa5491a66 +[NSArchiver archivedDataWithRootObject:] + 141
    8   coverTreeDemo                       0x0000000100003f3b _TFC13coverTreeDemo8Document4datafzT6ofTypeSS_V10Foundation4Data + 491
    9   coverTreeDemo                       0x000000010000402b _TToFC13coverTreeDemo8Document4datafzT6ofTypeSS_V10Foundation4Data + 91
    10  AppKit                              0x00007fffa190121c -[NSDocument writeToURL:ofType:error:] + 812
    11  AppKit                              0x00007fffa1900ead -[NSDocument writeToURL:ofType:forSaveOperation:originalContentsURL:error:] + 445
    12  AppKit                              0x00007fffa208bbb1 -[NSDocument(NSDocumentSaving) _writeSafelyToURL:ofType:forSaveOperation:forceTemporaryDirectory:error:] + 915
    13  AppKit                              0x00007fffa208c8b7 -[NSDocument(NSDocumentSaving) _writeSafelyToURL:ofType:forSaveOperation:error:] + 28
    14  AppKit                              0x00007fffa190089e -[NSDocument writeSafelyToURL:ofType:forSaveOperation:error:] + 355
    15  AppKit                              0x00007fffa20978c5 __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_2.1116 + 233
    16  AppKit                              0x00007fffa20977cd __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke.1113 + 454
    17  AppKit                              0x00007fffa2095903 __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke_2.969 + 2071
    18  Foundation                          0x00007fffa56e8e48 __85-[NSFileCoordinator(NSPrivate) _coordinateWritingItemAtURL:options:error:byAccessor:]_block_invoke.404 + 226
    19  Foundation                          0x00007fffa56e88ab -[NSFileCoordinator(NSPrivate) _withAccessArbiter:invokeAccessor:orDont:andRelinquishAccessClaim:] + 493
    20  Foundation                          0x00007fffa557e206 -[NSFileCoordinator(NSPrivate) _coordinateWritingItemAtURL:options:error:byAccessor:] + 862
    21  AppKit                              0x00007fffa2092dd0 -[NSDocument(NSDocumentSaving) _fileCoordinator:coordinateReadingContentsAndWritingItemAtURL:byAccessor:] + 387
    22  AppKit                              0x00007fffa20950d4 __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke.964 + 544
    23  AppKit                              0x00007fffa209462b __85-[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:]_block_invoke + 508
    24  AppKit                              0x00007fffa1b2abd6 -[NSDocument(NSDocumentSerializationAPIs) continueFileAccessUsingBlock:] + 222
    25  AppKit                              0x00007fffa1b2b477 -[NSDocument(NSDocumentSerializationAPIs) _performFileAccess:] + 782
    26  AppKit                              0x00007fffa2094429 -[NSDocument(NSDocumentSaving) _saveToURL:ofType:forSaveOperation:completionHandler:] + 92
    27  AppKit                              0x00007fffa194b2a8 __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2 + 256
    28  AppKit                              0x00007fffa18ba1e2 -[NSDocument _commitEditingThenContinue:] + 474
    29  AppKit                              0x00007fffa18b9fff -[NSDocument _commitEditingWithDelegate:didSomethingSelector:contextInfo:thenContinue:] + 92
    30  AppKit                              0x00007fffa194b196 __85-[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke + 444
    31  AppKit                              0x00007fffa1b2a305 -[NSDocument(NSDocumentSerializationAPIs) performActivityWithSynchronousWaiting:usingBlock:cancellationHandler:] + 475
    32  AppKit                              0x00007fffa194afd4 -[NSDocument saveToURL:ofType:forSaveOperation:delegate:didSaveSelector:contextInfo:] + 113
    33  AppKit                              0x00007fffa2090ff1 __104-[NSDocument(NSDocumentSaving) _runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke.595 + 113
    34  AppKit                              0x00007fffa1b2a4d3 -[NSDocument(NSDocumentSerializationAPIs) _continueActivityUsingBlock:] + 320
    35  AppKit                              0x00007fffa2090de5 __104-[NSDocument(NSDocumentSaving) _runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke_2.580 + 506
    36  AppKit                              0x00007fffa209097c __104-[NSDocument(NSDocumentSaving) _runModalSavePanelForSaveOperation:delegate:didSaveSelector:contextInfo:]_block_invoke.561 + 1500
    37  AppKit                              0x00007fffa1c558b9 -[NSSavePanel _didEndSheet:returnCode:contextInfo:] + 95
    38  AppKit                              0x00007fffa17c3b84 -[NSWindow _endWindowBlockingModalSession:returnCode:] + 308
    39  AppKit                              0x00007fffa1c581c6 -[NSSavePanel overwriteAlertDidEnd:returnCode:contextInfo:] + 256
    40  AppKit                              0x00007fffa197a1e3 -[NSAlert didEndAlert:returnCode:contextInfo:] + 90
    41  AppKit                              0x00007fffa17c3b84 -[NSWindow _endWindowBlockingModalSession:returnCode:] + 308
    42  AppKit                              0x00007fffa18239e3 -[NSAlert buttonPressed:] + 107
    43  libsystem_trace.dylib               0x00007fffb984f3a7 _os_activity_initiate_impl + 53
    44  AppKit                              0x00007fffa1cd0721 -[NSApplication(NSResponder) sendAction:to:from:] + 456
    45  AppKit                              0x00007fffa17b4cc4 -[NSControl sendAction:to:] + 86
    46  AppKit                              0x00007fffa17b4bec __26-[NSCell _sendActionFrom:]_block_invoke + 136
    47  libsystem_trace.dylib               0x00007fffb984f3a7 _os_activity_initiate_impl + 53
    48  AppKit                              0x00007fffa17b4b44 -[NSCell _sendActionFrom:] + 128
    49  AppKit                              0x00007fffa17f7539 -[NSButtonCell _sendActionFrom:] + 98
    50  libsystem_trace.dylib               0x00007fffb984f3a7 _os_activity_initiate_impl + 53
    51  AppKit                              0x00007fffa17b3426 -[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2481
    52  AppKit                              0x00007fffa17f7272 -[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 798
    53  AppKit                              0x00007fffa17b1ddb -[NSControl mouseDown:] + 832
    54  AppKit                              0x00007fffa1e4c24f -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 6341
    55  AppKit                              0x00007fffa1e48a6c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 1942
    56  AppKit                              0x00007fffa1e47f0a -[NSWindow(NSEventRouting) sendEvent:] + 541
    57  AppKit                              0x00007fffa1ccc681 -[NSApplication(NSEvent) sendEvent:] + 1145
    58  AppKit                              0x00007fffa1547427 -[NSApplication run] + 1002
    59  AppKit                              0x00007fffa1511e0e NSApplicationMain + 1237
    60  coverTreeDemo                       0x0000000100002cbd main + 13
    61  libdyld.dylib                       0x00007fffb961d235 start + 1
)
1

There are 1 best solutions below

3
On BEST ANSWER

The problem is that you refer to in your NSDocument subclass to NSArchiver and NSUnarchiver. That's wrong. These classes are deprecated. You should be using NSKeyedArchiver and NSKeyedUnarchiver, which replace them. The docs are quite clear about this:

In macOS 10.2 and later, NSArchiver and NSUnarchiver have been replaced by NSKeyedArchiver and NSKeyedUnarchiver respectively