Как использовать делегатов с 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 уже закончен, больше не может декодировать

Это также имеет смысл для кодирования копий.