在`NSKeyedArchiverDelegate`中没有调用`cannotDecodeObjectOfClassName`

时间:2017-04-26 07:45:13

标签: swift exception delegates nskeyedunarchiver nssecurecoding

我正在尝试捕获var myData = [{ company: "ABC", url: "www.abc.com", type: "internal" }, { company: "CDE", url: "www.cde.com", type: "internal" }, { company: "DEF", url: "www.def.com", type: "external" }, { company: "EFG", url: "www.efg.com", type: "internal" }, { company: "FGH", url: "www.fgh.com", type: "external" }]; $('#createData').click(function() { createDisplay(); }); function createDisplay() { myData.forEach(function(obj) { $('.container').append( $('<div>').addClass('box').append( $('<label>').text('Company Website: '), $('<a>').addClass('compUrl').attr('href', obj.url).text(obj.company), obj.type == 'external' ? $('<br /><button>').addClass('edit-btn').text('Edit').attr({"data-toggle":"modal", "data-target":"#updateData"}) : '' ) ) }); } $(document).on('click', '.edit-btn', function(){ var index = getIndex(this); $("#updateForm").submit(function(index){ updateData(index); return false; }); }); function getIndex(item){ return $(item).parents('.box').index(); } function updateData(obj) { companyName = $('#companyName').val(); companyUrl = $('#companyUrl').val(); var upObj = { company: companyName, url: companyUrl, type: "external" } myData.splice(index, 1, upObj); createDisplay(); }取消归档异常.box { height: 100px; background-color: skyblue; border: 1px solid black; margin-top: 5px; },其中通过<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/> <div class="container"> </div> <button id="createData">Create divs</button> <!-- Modal --> <div class="modal fade" id="updateData" tabindex="-1" role="dialog" aria-labelledby="update-data" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <!-- Modal Header --> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal"> <span aria-hidden="true">&times;</span> <span class="sr-only">Close</span> </button> <h4 class="modal-title" id="myModalLabel">Update Data</h4> </div> <form id="updateForm"> <!-- Modal Body --> <div class="modal-body"> <div class="form-group"> <label class="col-sm-4 control-label" for="companyName">Company Name</label> <div class="col-sm-8"> <input type="text" class="form-control" id="companyName" placeholder="Company Name" required/> </div> </div> <div class="form-group"> <label class="col-sm-4 control-label" for="companyUrl">Password</label> <div class="col-sm-8"> <input type="url" class="form-control" id="companyUrl" placeholder="Company URL" required/> </div> </div> </div> <!-- Modal Footer --> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal"> Close </button> <button class="btn btn-primary"> Save changes </button> </div> </form> </div> </div> </div>协议安全地解码未知类。

我使用的解决方案基于相关的NSKeyedUnarchiverDelegate SO post,通过实施委托协议NSKeyedUnarchiver,因此我可以通过NSInvalidUnarchiveOperationException收听并回复异常。但是,在解码过程中遇到未知类时,似乎不会调用此委托方法。

以下是我用于安全取消归档数组对象的代码段。

NSSecureCoding

我的NSKeyedUnarchiverDelegate的实现就像我指出的原始NSKeyedUnarchiverDelegate SO post一样。在我的设置下,unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)不会抛出异常,而是引发运行时异常:

func securelyUnarchiveArrayOfCustomObject(from url: URL, for key: String) -> [MyCustomClass]? {
    guard let data = try? Data(contentsOf: url) else {
        os_log("Unable to locate data at given url.path: %@", log: OSLog.default, type: .error, url.path)
        return nil
    }

    let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
    let delegate = UnarchiverDelegate()     // Prevents `NSInvalidUnarchiveOperationException` crash
    unarchiver.delegate = delegate
    unarchiver.requiresSecureCoding = true  // Prevents object substitution attack

    let allowedClasses = [NSArray.self] // Will decode without problem if using [NSArray.self, MyCustomClass.self]
    let decodedObject = unarchiver.decodeObject(of: allowedClasses, forKey: key)
    let images = decodedObject as! [ImageWithCaption]?
    unarchiver.finishDecoding()

    return images
}

根据its documentation,这应该是UnarchiverDelegate decodeObject(of: allowedClasses, forKey: key)应该调用的异常类型:

  

通知代理在解码期间具有给定名称的类不可用。

但在我的情况下,不使用上面的代码段调用此方法(即使在解码没有遇到问题时,也会正常调用其他委托方法,如'NSInvalidUnarchiveOperationException', reason: 'value for key 'NS.objects' was of unexpected class 'MyCustomClassProject.MyCustomClass'. Allowed classes are '{( NSArray )}'.' NSKeyedUnarchiverDelegate。 / p>

与原帖不同,我不能使用像unarchiver(_:cannotDecodeObjectOfClassName:originalClasses:)这样的类函数,我可以使用unarchiverWillFinish(_:)来处理异常,因为我需要使用unarchiver(_:didDecode:)支持安全编码和解码协议,,如讨论here。这迫使我使用decodeTopLevelObjectForKey,它不会抛出我可以处理的任何异常,而且,在抛出导致应用程序崩溃的运行时异常之前,它不会通知我的委托。

在什么情况下实际调用了委托方法try??如何在NSSecureCoding设置下监听decodeObject(of:forKey)并对其做出反应,以便在解码不成功时避免运行时崩溃?

1 个答案:

答案 0 :(得分:0)

有人在Apple Dev Forum上帮助过我。有关详细信息,请参阅:

https://forums.developer.apple.com/thread/76664