NSKeyedUnarchiver.decodeObject
will cause a crash / SIGABRT
if the original class is unknown. The only solution I have seen to catching this issue dates from Swift's early history and required using Objective C (also pre-dated Swift 2's implementation of guard
, throws
, try
& catch
). I could figure out the Objective C route - but I would prefer to understand a Swift-only solution if possible.
For example - the data has been encoded with NSPropertyListFormat.XMLFormat_v1_0
. The following code will fail at unarchiver.decodeObject()
if the class of the encoded data is unknown.
//...
let dat = NSData(contentsOfURL: url)!
let unarchiver = NSKeyedUnarchiver(forReadingWithData: dat)
//it will crash after this if the class in the xml file is not known
if let newListCollection = (unarchiver.decodeObject()) as? List {
return newListCollection
} else {
return nil
}
//...
I am looking for a Swift 2 only way to test whether the data is valid before attempting .decodeObject
- since .decodeObject
has no throws
- which means that try
- catch
does not seem to be an option in Swift (methods without throws
cannot be wrapped AFAIK). Or else an alternative way of decoding the data which will throw an error I can catch if the decode fails. I want the user to be able to import a file from iCloud drive or Dropbox - therefore it needs to be properly validated. I cannot assume that the encoded data is safe.
The NSKeyedUnarchiver
methods .unarchiveTopLevelObjectWithData
& .validateValue
both have throws
. Is there perhaps some way that these could be used? I cannot work out how to even begin to attempt to implement validateValue
in this context. Is this even a possible route? Or should I be looking to one of the other methods for a solution?
Or does anyone know an alternative Swift 2 only way of addressing this issue? I believe that the key I am interested in is probably entitled $classname
- but TBH I am out of my depth with respect to trying to work out how to implement validateValue
- or even whether that would be the correct route to persevere with. I have the sense that I am missing something obvious.
EDIT: Here is a solution - thanks to rintaro's great answer(s) below
The initial answer solved the issue for me - i.e. implementing a delegate.
For now however I have gone with a solution built around rintaro's additional edited response as follows:
//...
let dat = NSData(contentsOfURL: url)!
let unarchiver = NSKeyedUnarchiver(forReadingWithData: dat)
do {
let decodedDataObject = try unarchiver.decodeTopLevelObject()
if let newListCollection = decodedDataObject as? List {
return newListCollection
} else {
return nil
}
}
catch {
return nil
}
//...
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…