I'm using NSKeyedArchiver
& NSKeyedUnarchiver
to store some complex data in Core-Data
and retrieve it later in my app.
This was working perfectly until now, but after migration, Swift 3.0
does not seem to be happy with my code.
I've this early in my code:
var firstArray = [Int](), secondArray = [CGFloat]()
.......
// stores some values in firstArray and also in secondArray.
.......
Here is how the code to store the data looks like:
let masterArray = [firstArray, secondArray] as [Any]
let dataForApp:NSData = NSKeyedArchiver.archivedData(withRootObject: masterArray) as NSData
entityFieldsDico = ["dataForAppArray":dataForApp]
// Use entityFieldsDico to save dataForApp in Core-Data under the key "dataForAppArray".
Here is how the code to retrieve the data looks like:
if let archiveData = dbRecord.value(forKey: "dataForAppArray") {
let archiveArray = NSKeyedUnarchiver.unarchiveObject(with: archiveData as! Data)
firstArray = (archiveArray as! Array)[0] as [Int]
secondArray = (archiveArray as! Array)[1] as [CGFloat]
}
The issue appears whith the code retrieving the data. It simply crashes at build time.
If I comment out those 2 lines:
//firstArray = (archiveArray as! Array)[0] as [Int]
//secondArray = (archiveArray as! Array)[1] as [CGFloat]
The program works, except for the fact that the data in firstArray & is (obviously) not available.
If I do not comment them out, then I get a crash, with a very long message ending with something like what lies below. (I add some ...(dots) to shorten the message.)
.............
0 swift 0x000000010d71fa3d PrintStackTraceSignalHandler(void*) + 45
1 swift 0x000000010d71f466 SignalHandler(int) + 470
2 libsystem_platform.dylib 0x00007fffa0c5a52a _sigtramp + 26
3 libsystem_platform.dylib 0x0000000000000003 _sigtramp + 1597659891
4 swift 0x000000010b25b4e3 swift::constraints::ConstraintGraphScope::~ConstraintGraphScope() + 899
5 swift 0x000000010b2f45f4 swift::constraints::ConstraintSystem::solveSimplified(llvm::SmallVectorImpl<swift::constraints::Solution>&, swift::FreeTypeVariableBinding) + 24868
...........
Objects-normal/arm64/UP_ViewController.dia -emit-dependencies-path /Users/me/Library/Developer/Xcode/DerivedData/TheApp-dszaazmmftlmwbicuwcwaplkjdfs/Build/Intermediates/TheApp.build/Debug-iphoneos/TheApp.build/Objects-normal/arm64/UP_ViewController.d -emit-reference-dependencies-path /Users/me/Library/Developer/Xcode/DerivedData/TheApp-dszaazmmftlmwbicuwcwaplkjdfs/Build/Intermediates/TheApp.build/Debug-iphoneos/TheApp.build/Objects-normal/arm64/UP_ViewController.swiftdeps -o /Users/me/Library/Developer/Xcode/DerivedData/TheApp-dszaazmmftlmwbicuwcwaplkjdfs/Build/Intermediates/TheApp.build/Debug-iphoneos/TheApp.build/Objects-normal/arm64/UP_ViewController.o -embed-bitcode-marker
1. While type-checking 'computeFunction' at /Users/me/Documents/iOS/TheApp/TheApp/UP_ViewController.swift:184:5
2. While type-checking expression at [/Users/me/Documents/iOS/TheApp/TheApp/UP_ViewController.swift:235:17 - line:235:66] RangeText="firstArray = (archiveArray as! Array)[0] as [Int]"
I anyone has experienced this kind of problem, please let me know how you solved it.
You need to cast your archiveArray
to Array<Array<Any>>
then you can get the array of array with contains Any
type value.
For your Solution is
if let archiveData = dbRecord.value(forKey: "dataForAppArray") {
if let archiveArray = NSKeyedUnarchiver.unarchiveObject(with: archiveData as! Data) as? Array<Array<Any>> {
firstArray = archiveArray[0] as! [Int]
secondArray = archiveArray[1] as! [CGFloat]
}
}
Let's take an example for batter understanding
var firstArray = [Int](), secondArray = [CGFloat]()
firstArray.append(1)
firstArray.append(1)
firstArray.append(1)
secondArray.append(1.1)
secondArray.append(1.2)
secondArray.append(1.3)
print(firstArray) //[1, 1, 1]
print(secondArray) //[1.1, 1.2, 1.3]
let masterArray = [firstArray, secondArray] as [Any] //[[1, 1, 1], [1.1, 1.2, 1.3]]
let dataForApp:NSData = NSKeyedArchiver.archivedData(withRootObject: masterArray) as NSData
Now unarchiveObject
which return Any
then print output so can differentiate both output.
let archiveArray1 = NSKeyedUnarchiver.unarchiveObject(with: dataForApp as Data)
print(archiveArray1!)
output will be
(
(
1,
1,
1
),
(
"1.1",
"1.2",
"1.3"
)
)
Now cast array to Array<Array<Any>>
if let archiveArray = NSKeyedUnarchiver.unarchiveObject(with: dataForApp as Data) as? Array<Array<Any>> {
print(archiveArray)
}
Output will be
[[1, 1, 1], [1.1, 1.2, 1.3]]
Hope you understand my point.