NSKeyedArchiver и NSKeyedUnarchiver/Swift 3.0

Я использую NSKeyedArchiver и NSKeyedUnarchiver для хранения некоторых сложных данных в Core-Data и их последующего извлечения в моем приложении. До сих пор это работало отлично, но после миграции Swift 3.0, похоже, не доволен моим кодом.

В моем коде это было раньше:

        var firstArray = [Int](), secondArray = [CGFloat]()
        .......
        // stores some values in firstArray and also in secondArray.
         .......

Вот как выглядит код для хранения данных:

        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".

Вот как выглядит код для получения данных:

    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]
    }

Проблема возникает с кодом, извлекающим данные. Он просто вылетает во время сборки.

Если я закомментирую эти две строки:

        //firstArray = (archiveArray as! Array)[0] as [Int]
        //secondArray = (archiveArray as! Array)[1] as [CGFloat]

Программа работает, за исключением того факта, что данные в firstArray& (очевидно) недоступны.

Если я их не закомментирую, то у меня вылетает очень длинное сообщение, заканчивающееся чем-то вроде того, что ниже. (Я добавляю несколько ...(точек), чтобы сократить сообщение.)

.............
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]"

Может кто сталкивался с такой проблемой, подскажите как вы ее решили.


person Michel    schedule 19.12.2016    source источник
comment
Проверить мой ответ   -  person jignesh Vadadoriya    schedule 20.12.2016


Ответы (1)


Вам нужно преобразовать archiveArray в Array<Array<Any>>, после чего вы сможете получить массив массива, содержащий значение типа Any.

Для вашего решения

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]
            }

}

Давайте возьмем пример для понимания теста

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

Теперь unarchiveObject, которые возвращают Any, затем выводят вывод, чтобы можно было различать оба вывода.

let archiveArray1 = NSKeyedUnarchiver.unarchiveObject(with: dataForApp as Data)
print(archiveArray1!)

вывод будет

(
        (
        1,
        1,
        1
    ),
        (
        "1.1",
        "1.2",
        "1.3"
    )
)

Теперь приведите массив к Array<Array<Any>>

if let archiveArray = NSKeyedUnarchiver.unarchiveObject(with: dataForApp as Data) as? Array<Array<Any>> {
            print(archiveArray)
}

Выход будет

[[1, 1, 1], [1.1, 1.2, 1.3]]

Надеюсь, вы понимаете мою точку зрения.

person jignesh Vadadoriya    schedule 20.12.2016
comment
Привет, твое решение кажется хорошим. Мне нужно работать над этим, чтобы заставить его работать. Моя первая попытка провалилась. Я буду держать вас в курсе. - person Michel; 20.12.2016
comment
с какой проблемой вы столкнулись при первом испытании? - person jignesh Vadadoriya; 20.12.2016
comment
Я только что закончил обновление Xcode до версии 8.2.1 для поддержки iOS 10.2. Я вернулся к проблеме. Позвольте мне посмотреть, что работает, а что нет, я соответствующим образом обновлю свой пост. - person Michel; 20.12.2016
comment
Теперь это работает. Большое спасибо! В моем первом испытании я не следил за некоторыми деталями вашего ответа. Исправление этой части сделало его гладким. - person Michel; 20.12.2016