Ios 转换为Swift 3中断自定义类编码/解码

Ios 转换为Swift 3中断自定义类编码/解码,ios,nsuserdefaults,swift3,nscoding,Ios,Nsuserdefaults,Swift3,Nscoding,因此,我刚刚将一个小应用程序从Swift 2.2转换为Swift 3。我已经摆脱了通常的错误和自动转换器后需要的清理,但我有一个运行时问题,我无法解决 我有一个自定义类,我正在使用NSCoding协议将它保存到NSUserDefaults。当我尝试从NSUserDefaults解码编码对象时,它在guard let duration=decoder.decodeObject(forKey:“duration”)上失败,因为?Int行作为持续时间打印为零。对标题字符串进行解码工作正常,但至少enc

因此,我刚刚将一个小应用程序从Swift 2.2转换为Swift 3。我已经摆脱了通常的错误和自动转换器后需要的清理,但我有一个运行时问题,我无法解决

我有一个自定义类,我正在使用NSCoding协议将它保存到NSUserDefaults。当我尝试从NSUserDefaults解码编码对象时,它在
guard let duration=decoder.decodeObject(forKey:“duration”)上失败,因为?Int
行作为持续时间打印为零。对标题字符串进行解码工作正常,但至少encode函数的那一行工作正常

这在2.2中运行良好,我找不到任何迹象表明Swift 3对NSCoding进行了更改。任何帮助都将不胜感激

class TimerModel: NSObject, NSCoding, AVAudioPlayerDelegate {

    var name: String
    var active: Bool
    var paused: Bool
    var duration: Int
    var remainingWhenPaused: Int?
    var timerEndTime: Date?
    var timerStartTime: Date?
    var audioAlert: AlertNoise
    var UUID: String
    var colorScheme: BaseColor
    var alarmRepetitions: Int
    var timerRepetitions: Int
    var currentTimerRepetition: Int
    var audioPlaying: Bool
    var player: AVAudioPlayer = AVAudioPlayer()
    var countDownTimer: Timer = Timer()
    var delegate: timerProtocol? = nil

    init(withName name: String, duration: Int, UUID: String, color: BaseColor, alertNoise: AlertNoise, timerRepetitions: Int, alarmRepetitions: Int) {
        self.name = name
        self.active = false
        self.paused = false
        self.duration = duration
        self.UUID = UUID
        self.audioAlert = alertNoise
        self.colorScheme = color
        self.alarmRepetitions = alarmRepetitions
        self.audioPlaying = false
        self.timerRepetitions = timerRepetitions
        self.currentTimerRepetition = 0

        super.init()
    }

    convenience override init() {
        self.init(withName: "Tap Timer 1", duration: 10, UUID: Foundation.UUID().uuidString, color: .Red, alertNoise: .ChurchBell, timerRepetitions: 1, alarmRepetitions: 0)
    }

    // MARK: NSCoding

    required convenience init? (coder decoder: NSCoder) {
        print("in init coder:")
        print("Name: \(decoder.decodeObject(forKey: "name"))")
        print("Duration: \(decoder.decodeObject(forKey: "duration"))")
        guard let name = decoder.decodeObject(forKey: "name") as? String
        else {
            print("init coder name guard failed")
            return nil
        }
        guard let duration = decoder.decodeObject(forKey: "duration") as? Int
        else {
            print("init coder duration guard failed")
            print("duration: \(decoder.decodeObject(forKey: "duration"))")
            return nil
        }
        guard let audioAlertRawValue = decoder.decodeObject(forKey: "audioAlert") as? String
        else {
            print("init coder audioAlert guard failed")
            return nil
        }
        guard let UUID = decoder.decodeObject(forKey: "UUID") as? String
        else {
            print("init coder UUID guard failed")
            return nil
        }
        guard let colorSchemeRawValue = decoder.decodeObject(forKey: "colorScheme") as? String
        else {
            print("init coder colorScheme guard failed")
            return nil
        }
        guard let alarmRepetitions = decoder.decodeObject(forKey: "alarmRepetitions") as? Int
        else {
            print("init coder alarmRepetitions guard failed")
            return nil
        }
        guard let timerRepetitions = decoder.decodeObject(forKey: "timerRepetitions") as? Int
        else {
            print("init coder timerRepetitions guard failed")
            return nil
        }

        guard let audioAlert = AlertNoise(rawValue: audioAlertRawValue)
            else{
                print("No AlertNoise rawValue case found")
                return nil
        }
        guard let colorScheme = BaseColor(rawValue: colorSchemeRawValue)
            else{
                print("No BaseColor rawValue case found")
                return nil
        }

        print("initCoder guards passed, initing timer")
        print("\(name), \(duration), \(UUID), \(colorScheme), \(audioAlert), \(timerRepetitions), \(alarmRepetitions)")

        self.init(withName: name, duration: duration, UUID: UUID, color: colorScheme, alertNoise: audioAlert, timerRepetitions: timerRepetitions, alarmRepetitions: alarmRepetitions)
    }

    func encode(with aCoder: NSCoder) {

        aCoder.encode(self.name, forKey: "name")
        aCoder.encode(self.duration, forKey: "duration")
        aCoder.encode(self.audioAlert.rawValue, forKey: "audioAlert")
        aCoder.encode(self.UUID, forKey: "UUID")
        aCoder.encode(self.colorScheme.rawValue, forKey: "colorScheme")
        aCoder.encode(self.alarmRepetitions, forKey: "alarmRepetitions")
        aCoder.encode(self.timerRepetitions, forKey: "timerRepetitions")
    }

因此,如果有点不直观,解决方案似乎很简单


因此,我使用通用方法
encode(self.ivar,forKey:“keyName”)
对类ivar进行编码,但是如果该ivar是int,则需要使用
decodeInteger(forKey:“keyName”)
对其进行解码-这也需要去掉保护语句,因为该方法返回非可选的。如果使用通才方法解码,那么必须使用特定整数的方法似乎很奇怪-Swift 2.2中不是这种情况。

SimonBarker的回答很好,它解决了我遇到的相同问题。我最终将他的解决方案应用到我自己的代码中,并对其进行了修改,以便使用泛型方法进行编码。您可以使用以下方法使用generalist方法“强制”编码:

func encode(_ objv: Any?, forKey key: String)
因此,在您的代码中,您可以使用:

aCoder.encode(self.name as Any?, forKey: "name")
这样,self.name被编码为一个对象,并且不会破坏您现有的代码,即:decoder.decodeObject(forKey:“name”)as?串


这可能不是最优雅的解决方案,但至少它对我来说是有效的,而无需更改在Swift 2.3中运行良好但在Swift 3中被破坏的代码…

init(withName…
不符合命名约定
init(name…
。在与Objective-C交互时,您可能会遇到问题。谢谢@vadian,我只是在复习命名约定“如果使用通才方法进行解码,则必须使用特定于整数的方法进行解码似乎很奇怪”这让我很头疼。同意@George,感觉像个bug,但老实说,我不打算再提交报告了,因为苹果可能不会解决它。根据我的观察decodeObject()对Int的解码很好?但必须改为decodeInteger()如果您现在有Int.Now,我想知道所有其他非可选类型。