3

I'm new to Swift (background in C++) and I'm trying to do a very simple thing: save a Bool. It works perfectly if I convert the bool to a string that is either "A" or "B" and then convert back but if I save the bool directly with encode and aDecoder the Bool comes back nil every time. Can't find anything about it on the internet.

As you can see below I simply substitute a string for a Bool and it works.

func boolwontsave(aBool:Bool) -> String {
    if aBool {
        return "A"
    }
    return "B"
}

func encode(with aCoder: NSCoder) {

    aCoder.encode(name, forKey: PropertyKey.name)
    aCoder.encode(number, forKey: PropertyKey.number)
    aCoder.encode(boolwontsave(aBool: ispresent), forKey: PropertyKey.present)

}

required convenience init?(coder aDecoder: NSCoder) {

    // The name is required. If we cannot decode a name string, the initializer should fail.
    guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
        os_log("Unable to decode the name for a player object.", log: OSLog.default, type: .debug)
        return nil
    }

    let number = aDecoder.decodeObject(forKey: PropertyKey.number) as? String

    guard let localpresent = aDecoder.decodeObject(forKey: PropertyKey.present) as? String else {
        print("got the nil")
        os_log("Unable to decode the ispresent for a player object.", log: OSLog.default, type: .debug)
        return nil
    }


    // Must call designated initializer.
    self.init(name:name, number:number, present: localpresent == "A")

}

Aren't Bools supposed to save? This seems inelegant.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • What do you mean by saying "save a bool". Also please provide a code where you're trying to retrieve your bool and it return nil. – inokey Nov 15 '18 at 15:17
  • A bigger question is why you are using `NSCoding` and `NSCoder` in Swift. Is there a reason you are not using the Swift `Codable` features instead? – rmaddy Nov 15 '18 at 16:26

2 Answers2

5

Use decodeBool(forKey key: String) instead of decodeObject(forKey: String)

DecodeBool decodes and returns a boolean value that was previously encoded with encode(_:forKey:) and associated with the string key.

aCoder.encode(true, forKey: PropertyKey.present)
aCoder.decodeBool(forKey: PropertyKey.present)
Raul Mantilla
  • 334
  • 1
  • 5
4

It's very easy to save a Bool if you are using the proper API.

In terms of NSCoding a Bool is not an object, there is a decodeBool(forKey method.

required convenience init?(coder aDecoder: NSCoder) {

    // The name is required. If we cannot decode a name string, the initializer should fail.
    guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
        os_log("Unable to decode the name for a player object.", log: OSLog.default, type: .debug)
        return nil
    }

    let number = aDecoder.decodeObject(forKey: PropertyKey.number) as? String
    let localpresent = aDecoder.decodeBool(forKey: PropertyKey.present)

    // Must call designated initializer.
    self.init(name:name, number:number, present: localpresent)

}

func encode(with aCoder: NSCoder) {
    aCoder.encode(name, forKey: PropertyKey.name)
    aCoder.encode(number, forKey: PropertyKey.number)
    aCoder.encode(ispresent, forKey: PropertyKey.present)
}

In Swift 4+ I'd prefer the native Codable protocol over constrained NSCoding.

  • NSCoding requires an class inherited from NSObject.
  • Codable can be used for any struct, class and enum which conforms to the protocol.
vadian
  • 274,689
  • 30
  • 353
  • 361
  • Thanks for all the quick answers. I'll convert to using Codable, which I think will also solve my other challenge around saving nested arrays. Thanks again everyone! – Sam Hawksworth Nov 15 '18 at 18:45