Swift 3 NSCoder 无法识别的选择器发送到实例

Posted

技术标签:

【中文标题】Swift 3 NSCoder 无法识别的选择器发送到实例【英文标题】:Swift 3 NSCoder unrecognized selector sent to instance 【发布时间】:2017-06-30 23:45:04 【问题描述】:

我正在尝试将自定义类的列表保存到用户默认值,并且在保存时我不断收到“无法识别的选择器发送到实例”错误。从用户默认值获取数组时我没有问题。

这是我用来保存到用户默认值的代码。

let userDefaults = UserDefaults.standard
        userDefaults.set(NSKeyedArchiver.archivedData(withRootObject: visitors), forKey: "signedInUsers")
        userDefaults.synchronize()

visitors 是一个访问者对象数组。

这是我的访客类。

class Visitor: NSObject 
    var name: String = ""
    var contactEmail: String = ""
    var company: String = ""
    var picture: UIImage = UIImage()
    var signature: UIImage = UIImage()
    var timeIn: String = ""
    var timeOut: String = ""
    var signedOut: Bool = false
    var otherQuestionsWithAnswers: [String] = []

    // MARK: NSCoding

    override init() 
        super.init()
    

    init(name: String, contactEmail: String, company: String, picture: UIImage, signature: UIImage,timeIn: String,timeOut: String,signedOut: Bool,otherQuestionsWithAnswers: [String]) 
        self.name = name
        self.contactEmail = contactEmail
        self.company = company
        self.picture = picture
        self.signature = signature
        self.timeIn = timeIn
        self.timeOut = timeOut
        self.signedOut = signedOut
        self.otherQuestionsWithAnswers = otherQuestionsWithAnswers
    

    required convenience init?(coder decoder: NSCoder) 
        guard let name = decoder.decodeObject(forKey: "name") as? String,
            let contactEmail = decoder.decodeObject(forKey: "contactEmail") as? String,
            let company = decoder.decodeObject(forKey: "company") as? String,
            let timeOut = decoder.decodeObject(forKey: "timeOut") as? String,
            let timeIn = decoder.decodeObject(forKey: "timeIn") as? String,
            let picture = decoder.decodeObject(forKey: "picture") as? UIImage,
            let signature = decoder.decodeObject(forKey: "signature") as? UIImage,
            let otherQuestionsWithAnswers = decoder.decodeObject(forKey: "otherQuestionsWithAnswers") as? [String],
            let signedOut = decoder.decodeObject(forKey: "signedOut") as? Bool
            else  return nil 

        self.init(
            name: name,
            contactEmail: contactEmail,
            company: company,
            picture: picture,
            signature: signature,
            timeIn: timeIn,
            timeOut: timeOut,
            signedOut: signedOut,
            otherQuestionsWithAnswers: otherQuestionsWithAnswers
        )
    

    func encodeWithCoder(coder: NSCoder) 
        coder.encode(name, forKey: "name")
        coder.encode(contactEmail, forKey: "contactEmail")
        coder.encode(company, forKey: "company")
        coder.encode(picture, forKey: "picture")
        coder.encode(signature, forKey: "signature")
        coder.encode(timeIn, forKey: "timeIn")
        coder.encode(timeOut, forKey: "timeOut")
        coder.encode(signedOut, forKey: "signedOut")
        coder.encode(otherQuestionsWithAnswers, forKey: "otherQuestionsWithAnswers")
    

感谢您的帮助。

编辑:

将类更改为此修复它。

import Foundation
import UIKit

// a question that the user has to answer
class Visitor: NSObject, NSCoding 
    var name: String = ""
    var contactEmail: String = ""
    var company: String = ""
    var picture: UIImage = UIImage()
    var signature: UIImage = UIImage()
    var timeIn: String = ""
    var timeOut: String = ""
    var signedOut: Bool = false
    var otherQuestionsWithAnswers: [String] = []

    // MARK: NSCoding

    override init() 
        super.init()
    

    init(name: String, contactEmail: String, company: String, picture: UIImage, signature: UIImage,timeIn: String,timeOut: String,signedOut: Bool,otherQuestionsWithAnswers: [String]) 
        self.name = name
        self.contactEmail = contactEmail
        self.company = company
        self.picture = picture
        self.signature = signature
        self.timeIn = timeIn
        self.timeOut = timeOut
        self.signedOut = signedOut
        self.otherQuestionsWithAnswers = otherQuestionsWithAnswers
    

    required init(coder decoder: NSCoder) 
        name = decoder.decodeObject(forKey: "name") as! String
        contactEmail = decoder.decodeObject(forKey: "contactEmail") as! String
        company = decoder.decodeObject(forKey: "company") as! String
        timeOut = decoder.decodeObject(forKey: "timeOut") as! String
        timeIn = decoder.decodeObject(forKey: "timeIn") as! String
        if let pictureTest = decoder.decodeObject(forKey: "picture") as? UIImage 
            picture = pictureTest
         else 
            picture = UIImage()
        
        if let sigTest = decoder.decodeObject(forKey: "picture") as? UIImage 
            signature = sigTest
         else 
            signature = UIImage()
        
        otherQuestionsWithAnswers = decoder.decodeObject(forKey: "otherQuestionsWithAnswers") as! [String]
        signedOut = decoder.decodeBool(forKey: "signedOut")
    

    public func encode(with aCoder: NSCoder) 
        aCoder.encode(name, forKey: "name")
        aCoder.encode(contactEmail, forKey: "contactEmail")
        aCoder.encode(company, forKey: "company")
        aCoder.encode(picture, forKey: "picture")
        aCoder.encode(signature, forKey: "signature")
        aCoder.encode(timeIn, forKey: "timeIn")
        aCoder.encode(timeOut, forKey: "timeOut")
        aCoder.encode(signedOut, forKey: "signedOut")
        aCoder.encode(otherQuestionsWithAnswers, forKey: "otherQuestionsWithAnswers")
    

【问题讨论】:

没有被识别的特定选择器是什么?请包含您看到的完整错误消息。 好问题。同样的问题。不错的代码。期待看到这个伟大问题的答案。 @ItaiFerber 说什么选择器无法识别? 你用的是什么swift版本? 'NSInvalidArgumentException', reason: '-[Visitor_Manager.Visitor encodeWithCoder:]: unrecognized selector sent to instance 0x14e33400' swift 3. 删除该功能后仍然说使用编码器进行编码 【参考方案1】:

您用于编码的函数不正确,必须是 func encode(with aCoder: NSCoder) 而不是 func encodeWithCoder(coder: NSCoder) ,因此请更改它并按预期工作

public func encode(with aCoder: NSCoder) 
    aCoder.encode(name, forKey: "name")
    aCoder.encode(contactEmail, forKey: "contactEmail")
    aCoder.encode(company, forKey: "company")
    aCoder.encode(picture, forKey: "picture")
    aCoder.encode(signature, forKey: "signature")
    aCoder.encode(timeIn, forKey: "timeIn")
    aCoder.encode(timeOut, forKey: "timeOut")
    aCoder.encode(signedOut, forKey: "signedOut")
    aCoder.encode(otherQuestionsWithAnswers, forKey: "otherQuestionsWithAnswers")

希望对你有帮助

【讨论】:

嗯...似乎仍然无法正常工作。感谢回复 @VincentLandolfi 你清理了你的项目并重试了吗?【参考方案2】:

您的访问者类应该首先从 NSObject 继承,然后是 NSCoding。如果没有 NSCoding,您将无法对自定义类进行编码和解码。这是我最近在项目中犯的一个错误,您的编码函数签名不正确。我相信这会解决这个问题。这是更正后的代码:

Swift 3 版本:-

class Visitor: NSObject, NSCoding 
    var name: String = ""
    var contactEmail: String = ""
    var company: String = ""
    var picture: UIImage = UIImage()
    var signature: UIImage = UIImage()
    var timeIn: String = ""
    var timeOut: String = ""
    var signedOut: Bool = false
    var otherQuestionsWithAnswers: [String] = []

func encode(with aCoder: NSCoder) 
//... encode here

【讨论】:

似乎仍然无法正常工作。感谢您的回复。 你能在那个守卫语句上设置一个断点,看看它是否返回 nil 吗? 试过了,好像什么都没有

以上是关于Swift 3 NSCoder 无法识别的选择器发送到实例的主要内容,如果未能解决你的问题,请参考以下文章

目标动作模式的快速无法识别的选择器

Swift 3:发送到实例 Xcode 8 的无法识别的选择器 [重复]

Swift 3:将无法识别的选择器发送到手势识别器实例

Swift - 无法识别的选择器到实例 - UITapGestureRecognizer

Swift:发送到实例的无法识别的选择器

Swift:手势识别器无法识别的选择器发送到实例