I can't figure it out.
mac os, Swift 5, Cocoa, drag n drop, NSPasteboard
first, this is not an NSCoding issue. It's an NSPasteboard issue. Which is gratuitously backwards. it may be related, but NSPasteboardWritable is different enough to be punishing all the way through, and similar enough to remind you all the way that it doesn't need to be this horrible.
my class supports the PasteboardWriting protocol.
public func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any?{
let coder = NSKeyedArchiver(requiringSecureCoding: false) // whatever. secure is fine.
//coder.
coder.encode(name, forKey: "name") // these work as expected.
coder.encode(hint, forKey: "hint")
coder.encode(selectedMode, forKey: "selectedMode") // this is where the problem starts
coder.encode(modes, forKey: "modes") // this one too.
coder.encode(baseMode, forKey: "baseMode") // and this one as well.
coder.encode(delegate, forKey:"delegate") // at the moment, this IS nil
coder.encode(rep, forKey: "rep") // this is also nil
coder.encode(subCons, forKey:"subCons") // and this is an empty array.
coder.finishEncoding()
let theData = coder.encodedData
return theData
}the properties : selectedMode, baseMode, and modes are all NSCoding compliant classes. In modes case, it's an array of the same class as baseMode and selectedMode. I have stepped through the code. They definetly get encoded.
then on decoding the coder reports that there is indeed an entry for the key, and proceeds to produce a nil value for it.
public required init?(pasteboardPropertyList propertyList: Any, ofType type: NSPasteboard.PasteboardType) {
super.init()
do {
let decoder = try NSKeyedUnarchiver(forReadingFrom: propertyList as! Data)
self.name = decoder.decodeObject(forKey: "name") as! String
self.hint = decoder.decodeObject(forKey: "hint") as! String
if decoder.containsValue(forKey: "selectedMode"){
self.selectedMode = (decoder.decodeObject(forKey: "selectedMode") as? BKLayConMode) // this always returns,and it returns a nil
}
if decoder.containsValue(forKey: "baseMode"){
if let b = (decoder.decodeObject(forKey: "baseMode") as? BKLayConMode){
self.baseMode = b
}
}
self.modes = (decoder.decodeObject(forKey: "modes") as! [BKLayConMode])
if decoder.containsValue(forKey: "rep"){
self.rep = (decoder.decodeObject(forKey: "rep") as? NSObject)
}
if decoder.containsValue(forKey: "delegate"){
self.delegate = (decoder.decodeObject(forKey:"delegate") as? BKLayConDelegate)
}
self.subCons = (decoder.decodeObject(forKey: "subCons") as! [BKLayerController])
// now we set it up.
self.createLayer()
for each in self.subCons{
each.registerForNotes(observer: self)
self.layer.addSublayer(each.layer)
}
if self.selectedMode != nil{
self.selectedMode.registerForNotes(observer: self)
}
self.baseMode.registerForNotes(observer: self)
} catch {
debugPrint("i screwed up the drag n drop pasteboard reading for BKLayerController.")
}
}I use conditional tests (which I WOULD comment, but the cursor no longer goes where I put it) to test for "selectedMode" "baseMode" and "modes" the archive Has those values set. It just returns nil for every one of them, and my NSCoding initWithCoder method (in the property's class) never gets called.
I don't want to be making my own NSKeyedArchiver, and doing all this myself. It's brutally difficult, punitive, gratuitously different, and required. You can't properly support drag n drop without making your own NSKeyedArchiver, and individually archiving the properties of the Object you need to drag. There's no other way. (Codable is out of bounds at the moment, so please... don;t even mention it)
I think I have done everything correctly here. There's certainly no docs, examples or tutorials that cover this subject. Anyone with experience that can see an obvious problem?