Как использовать делегатов с NSKeyedUnarchiver?
Я использую NSKeyedUnarchiver для разблокирования объекта и хотел бы использовать делегатов (NSKeyedUnarchiverDelegate), но мои делегаты не вызываются. Архивирование и Unarchiving работает нормально, но делегаты (unarchiver и unarchiverDidFinish) не вызываются. Может кто-нибудь помочь?
У меня есть следующая реализация:
class BlobHandler: NSObject , NSKeyedUnarchiverDelegate{
func load() -> MYOBJECTCLASS{
let data:NSData? = getBlob();
var mykeyedunarchiver:NSKeyedUnarchiver=NSKeyedUnarchiver(forReadingWithData: data!);
mykeyedunarchiver.delegate = self;
let temp=mykeyedunarchiver.decodeObjectForKey("rootobject")
// No delegates are called
if temp==nil {
blobsexists=false;
}else{
objectreturn = temp! as! MYOBJECTCLASS;
return objectreturn;
}
}
func save1(myobject:MYOBJECTCLASS){
let data = NSMutableData()
var keyedarchiver:NSKeyedArchiver=NSKeyedArchiver(forWritingWithMutableData: data);
keyedarchiver.encodeObject(maptheme, forKey: "rootobject");
let bytes = data.bytes;
let len=data.length;
saveblob(bytes);
}
Следующие делегаты, которые также реализованы в моем Blobhandler, никогда не вызываются:
func unarchiver(unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass? {
print("I am in unarchiver !");
return nil;
}
func unarchiverDidFinish(_ unarchiver: NSKeyedUnarchiver){
print("I am in unarchiverDidFinish ! ");
}
Ответы
Ответ 1
Я не знаю, что это было, но он работал после чистого и перестроенного проекта.
Я замечаю в разных случаях, что сборки не синхронизируются иногда. Иногда есть код, который находится в XCode, но он не выполняется. Звучит невероятно, но я думаю, что это правда.
XCode 7.2
Ответ 2
Я думаю, что первая функция никогда не вызывается, так как вы фактически не пишете "cannotDecodeObjectOfClassName" вообще, так как вы только пытались распаковать ранее заархивированные данные. Вы можете попробовать этот метод (или что-то требует имя класса) для проверки вашего решения (кормить класс не соответствует NSCoding):
unarchiver.decodeObjectOfClass(cls: NSCoding.Protocol, forKey: String)
Второй немного сложнее. Я пробовал этот метод в аналогичной ситуации, и выяснилось, что unarchiverDidFinish вызывается только тогда, когда выполняется полная раскрепочная работа и, вероятно, до ее уничтожения. Например, у меня был класс NSCoding, и инициатор удобства похож на
required convenience init?(coder aDecoder: NSCoder) {
let unarchiver = aDecoder as! NSKeyedUnarchiver
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
unarchiver.delegate = appDelegate.uad
let name = unarchiver.decodeObjectForKey(PropertyKey.nameKey) as! String
print(321)
self.init(name: name, photo: photo, rating: rating)
}
uad - это экземпляр класса:
class UAD:NSObject, NSKeyedUnarchiverDelegate {
func unarchiverDidFinish(unarchiver: NSKeyedUnarchiver) {
print(123)
}
}
И в контроллере представления процесс загрузки похож на
func load() -> [User]? {
print(1)
let ret = NSKeyedUnarchiver.unarchiveObjectWithFile(ArchiveURL.path!) as? [User]
print(2)
return ret
}
И результат выглядит так:
1
321
321
321
321
321
123
2
После завершения загрузки группы пользователей, unarchiverDidFinish, наконец, получил вызов один раз. Обратите внимание, что это функция класса, и для завершения этого предложения создается анонимный экземпляр:
NSKeyedUnarchiver.unarchiveObjectWithFile(ArchiveURL.path!) as? [User]
Поэтому я действительно считаю, что эта функция вызывается только до того, как она будет уничтожена, или завершена группа функций обратного вызова.
Я не совсем уверен, так ли это для вас. Вы можете попытаться сделать свой объект unarchiver глобальным и уничтожить его после завершения загрузки, чтобы узнать, вызвана ли эта функция.
Исправьте меня, если что-то не так.
Ответ 3
Чтобы сделать правильный вызов unarchiverWillFinish:
и unarchiverDidFinish:
, мы должны вызывать finishDecoding
, когда завершено декодирование.
Как только у вас есть настроенный объект декодера, чтобы декодировать объект или элемент данных, используйте метод decodeObjectForKey:
. Когда закончите декодировать архив с ключом, вы должны вызывать finishDecoding
, прежде чем выпускать unarchiver.
Мы уведомляем делегата об экземпляре NSKeyedUnarchiver и выполняем любые заключительные операции в архиве, используя этот метод. И как только этот метод вызывается, согласно официальной документации Apple, наш unarchiver не может декодировать какие-либо дополнительные значения. Мы получим следующее сообщение, если мы продолжим выполнение любой операции декодирования после вызова finishDecoding
:
*** - [NSKeyedUnarchiver decodeObjectForKey:]: unarchive уже закончен, больше не может декодировать
Это также имеет смысл для кодирования копий.