-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance - ios

Getting error when trying to utilize NSCoder
Player.swift:
class Player: NSObject, NSCoding {
private var _playerName: String!
private var _playerScore: Int!
private var _playerColor: PlayerColor! //PlayerColor is an enum
var playerName: String {
get {
return _playerName
}
set {
_playerName = newValue
}
}
var playerScore: Int {
get {
return _playerScore
}
set {
_playerScore = newValue
}
}
var playerColor: PlayerColor {
get {
return _playerColor
}
set {
_playerColor = newValue
}
}
init(playerName: String, playerScore: Int, playerColor: PlayerColor) {
_playerName = playerName
_playerScore = playerScore
_playerColor = playerColor
}
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let score = aDecoder.decodeInteger(forKey: "score")
let color = aDecoder.decodeObject(forKey: "color") as! PlayerColor
self.init(playerName: name, playerScore: score, playerColor: color)
}
func encode(with aCoder: NSCoder){
aCoder.encode(playerName, forKey: "name")
aCoder.encode(playerScore, forKey: "score")
aCoder.encode(playerColor, forKey: "color")
}
}
in PlayerStore.swift:
// Storage Functions
func savePlayers(){
let encodedData = NSKeyedArchiver.archivedData(withRootObject: _playerArray) // _playerarray is a [Player] the very object I want to store/retrieve at will
defaults.set(encodedData, forKey: playerKeyForDefaults) //defaults is just var NSUserDefaults.standard
defaults.synchronize()
}
func loadPlayers(){
if let decoded = defaults.object(forKey: playerKeyForDefaults) as? NSData {
let array = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data) as! [Player]
_playerArray = array
}
}

Here's the solution I implemented:
Player.swift:
import Foundation
class Player: NSObject, NSCoding {
private var name: String!
private var score: Int!
private var color: String!
var playerName: String {
get {
return name
}
set {
name = newValue
}
}
var playerScore: Int {
get {
return score
}
set {
score = newValue
}
}
var playerColor: String {
get {
return color
}
set {
color = newValue
}
}
init(playerName: String, playerScore: Int, playerColor: String) {
name = playerName
score = playerScore
color = playerColor
}
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let score = aDecoder.decodeObject(forKey: "score") as! Int
let color = aDecoder.decodeObject(forKey: "color") as! String
self.init(playerName: name, playerScore: score, playerColor: color)
}
func encode(with aCoder: NSCoder){
aCoder.encode(name, forKey: "name")
aCoder.encode(score, forKey: "score")
aCoder.encode(color, forKey: "color")
}
}
PlayerStore.swift:
func savePlayers(){
let encodedData = NSKeyedArchiver.archivedData(withRootObject: _playerArray)
defaults.set(encodedData, forKey: playerKeyForDefaults)
}
func loadPlayers(){
if let decoded = defaults.object(forKey: playerKeyForDefaults) as? NSData {
let array = NSKeyedUnarchiver.unarchiveObject(with: decoded as Data) as! [Player]
_playerArray = array
}
}

You can also use this approach using Enum rawValue. It might help you to archivedData and unarchiveObject a complete model object.
Color Enum With Hex value:
enum PlayerColor: String {
case red = "#FF0000"
case silver = "#C0C0C0"
case gray = "#808080"
case black = "#000000"
var description: String {
return self.rawValue
}
}
import Foundation
class Player: NSObject, NSCoding {
private var name: String!
private var score: Int!
private var color: PlayerColor!
init(playerName: String, playerScore: Int, playerColor: PlayerColor) {
name = playerName
score = playerScore
color = playerColor
}
required convenience init(coder aDecoder: NSCoder) {
let name = aDecoder.decodeObject(forKey: "name") as! String
let score = aDecoder.decodeObject(forKey: "score") as! Int
if let value = aDecoder.decodeObject(forKey: "color") as? String{
color = PlayerColor(rawValue: value)
}
self.init(playerName: name, playerScore: score, playerColor: color)
}
func encode(with aCoder: NSCoder){
aCoder.encode(name, forKey: "name")
aCoder.encode(score, forKey: "score")
let value = color!.description
aCoder.encode(value, forKey: "color")
}
}

Related

How to fix this error "-[__SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x2834ca6f0"?

I have an error when I try to encode my object. I've found lot of answers, but that didn't work for me :(
I cut my code, leaving only the important
This is main class "City" with tuple and Arrays of "cityHourlyForecast" and "cityDailyForecast" in it
class City: NSObject, NSCoding {
var name: String
var currentWeather: (isDayTime: Bool, lastUpdate: Date?, temp_C: Int, temp_F: Int, weatherIcon: String, weatherText: String) =
( isDayTime: true,
lastUpdate: nil,
temp_C: 0,
temp_F: 0,
weatherIcon: "1",
weatherText: "" )
var hourlyForecast: Array<cityHourlyForecast> = []
var dailyForecast: Array<cityDailyForecast> = []
init(name: String) {
self.name = name
}
// MARK: NSCoding
func encode(with coder: NSCoder) {
coder.encode(self.name, forKey: "name")
coder.encode(self.currentWeather, forKey: "currentWeather")
coder.encode(self.hourlyForecast, forKey: "hourlyForecast")
coder.encode(self.dailyForecast, forKey: "dailyForecast")
}
required convenience init?(coder: NSCoder) {
guard let name = coder.decodeObject(forKey: "name") as? String
else { return nil }
self.init(name: name)
if let currentWeather = coder.decodeObject(forKey: "currentWeather") {
self.currentWeather = currentWeather as! (isDayTime: Bool, lastUpdate: Date?, temp_C: Int, temp_F: Int, weatherIcon: String, weatherText: String)
}
if let hourlyForecast = coder.decodeObject(forKey: "hourlyForecast") {
self.hourlyForecast = hourlyForecast as! Array<cityHourlyForecast>
}
if let dailyForecast = coder.decodeObject(forKey: "dailyForecast") {
self.dailyForecast = dailyForecast as! Array<cityDailyForecast>
}
}
}
cityHourlyForecast:
class cityHourlyForecast: NSObject, NSCoding {
var dateTime: String
var temp_C: Int
init (dateTime: String, temp_C: Int) {
self.dateTime = dateTime
self.temp_C = temp_C
}
func encode(with coder: NSCoder) {
coder.encode(dateTime, forKey: "dateTime")
coder.encode(temp_C, forKey: "temp_C")
}
required convenience init?(coder: NSCoder) {
guard let dateTime = coder.decodeObject(forKey: "dateTime") as? String,
let temp_C = coder.decodeObject(forKey: "temp_C") as? Int
else { return nil }
self.init(dateTime: dateTime, temp_C: temp_C)
}
}
cityDailyForecast:
class cityDailyForecast: NSObject, NSCoding {
var dateTime: String
var temp_min_C: Int
var temp_max_C: Int
init (dateTime: String, temp_min_C: Int, temp_max_C: Int) {
self.dateTime = dateTime
self.temp_min_C = temp_min_C
self.temp_max_C = temp_max_C
}
func encode(with coder: NSCoder) {
coder.encode(dateTime, forKey: "dateTime")
coder.encode(temp_min_C, forKey: "temp_min_C")
coder.encode(temp_max_C, forKey: "temp_max_C")
}
required convenience init?(coder: NSCoder) {
guard let dateTime = coder.decodeObject(forKey: "dateTime") as? String,
let temp_min_C = coder.decodeObject(forKey: "temp_min_C") as? Int,
let temp_max_C = coder.decodeObject(forKey: "temp_max_C") as? Int
else { return nil }
self.init(dateTime: dateTime, temp_min_C: temp_min_C, temp_max_C: temp_max_C)
}
}
And here I try to initialize array of "City" with getter and setter
var AccuCities:Array<City> {
get{
if let array = UserDefaults.standard.object(forKey: "Cities") as? Data {
let decodedArray = NSKeyedUnarchiver.unarchiveObject(with: array)
return decodedArray as! Array<City>
} else {
return []
}
}
set{
let encodedArray = NSKeyedArchiver.archivedData(withRootObject: newValue)
UserDefaults.standard.set(encodedArray, forKey: "Cities")
UserDefaults.standard.synchronize()
}
}
What should I do to encode my array of "City" and save it to UserDefaults?

NSKeyedArchiver.archivedData does not work in Swift 3 iOS

When try to encode my custom object in iOS swift get this error from Xcode 8.3
unrecognized selector sent to instance 0x60800166fe80
*** -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
And my code like this:
import UIKit
import Foundation
class Place: NSObject {
func setCustomObject(CustomObject obj:Any,Key key:String) {
let encodedObject : Data = NSKeyedArchiver.archivedData(withRootObject: obj)
UserDefaults.standard.set(encodedObject, forKey: key)
}
}
Here's an example how to make an object to conform to NSCoding. Basically you need to provide implementation of two methods - required convenience init?(coder decoder: NSCoder) and encode(with aCoder: NSCoder)
class Book: NSObject, NSCoding {
var title: String?
var pageCount: Int?
// Memberwise initializer
init(title: String,pageCount: Int) {
self.title = title
self.pageCount = pageCount
}
// MARK: NSCoding
// Here you will try to initialize an object from archve using keys you did set in `encode` method.
required convenience init?(coder decoder: NSCoder) {
guard let title = decoder.decodeObject(forKey: "title") as? String else { return nil }
self.init(title: title, pageCount: decoder.decodeInteger(forKey: "pageCount"))
}
// Here you need to set properties to specific keys in archive
func encode(with aCoder: NSCoder) {
aCoder.encode(self.title, forKey: "title")
aCoder.encodeCInt(Int32(self.pageCount), forKey: "pageCount")
}
}
Also I would recommend changing your setCustomObject method to this:
func setCustomObject(obj:NSCoding, key:String) {
let encodedObject : Data = NSKeyedArchiver.archivedData(withRootObject: obj)
UserDefaults.standard.set(encodedObject, forKey: key)
}
This way compiler prevent you passing NSKeyedArchiver an object that does not conform to NSCoding protocol.
If you don't want to provide all properties in the init method you can use default values:
init(title : String? = nil, pageCount: Int? = nil){
self.title = title
self.pageCount = pageCount
}
Now you can just init your object without any properties. Like that Book()
Here is the solutions, you have to implement the two methods
Encode Method
func encode(with aCoder: NSCoder)
Decoding method
required init?(coder aDecoder: NSCoder)
Complete Example code
class User: NSObject , NSCoding
{
var userID : Int = 0
var name : String = ""
var firstName : String = ""
var lastName : String = ""
var username : String = ""
var email : String = ""
override init(){
super.init();
}
func encode(with aCoder: NSCoder) {
aCoder.encode(self.userID, forKey: "id");
aCoder.encode(self.firstName, forKey: "first_name");
aCoder.encode(self.lastName, forKey: "last_name");
aCoder.encode(self.name, forKey: "name");
aCoder.encode(self.username,forKey: "username");
aCoder.encode(self.email, forKey: "email");
}
required init?(coder aDecoder: NSCoder) {
super.init()
self.userID = aDecoder.decodeInteger(forKey: "id");
self.firstName = aDecoder.decodeObject(forKey: "first_name") as! String;
self.lastName = aDecoder.decodeObject(forKey: "last_name") as! String;
self.name = aDecoder.decodeObject(forKey: "name") as! String
self.username = aDecoder.decodeObject(forKey: "username") as! String
self.email = aDecoder.decodeObject(forKey: "email") as! String;
}
init(data : [String: AnyObject]) {
super.init()
self.userID = String.numberValue(data["user_id"]).intValue;
self.firstName = String.stringValue(data["first_name"]);
self.lastName = String.stringValue(data["last_name"]);
self.email = String.stringValue(data["email"]);
self.username = String.stringValue(data["user_name"]);
}
class func loadLoggedInUser() -> User {
if let archivedObject = UserDefaults.standard.object(forKey:"CurrentUserAcc"){
if let user = NSKeyedUnarchiver.unarchiveObject(with: (archivedObject as! NSData) as Data) as? User {
return user;
}
}
return User()
}
func saveUser(){
let archivedObject : NSData = NSKeyedArchiver.archivedData(withRootObject: self) as NSData
UserDefaults.standard.set(archivedObject, forKey: "CurrentUserAcc");
UserDefaults.standard.synchronize();
}
func deleteUser(){
UserDefaults.standard.set(nil, forKey: "CurrentUserAcc")
UserDefaults.standard.synchronize();
}
}

Saving Array of Struct with NSKeyedArchiver and Userdefault in which object conform to NSCoding

As a Protocol oriented programming concept, I have created my model with Struct.
I want to save Array of "Struct" into Userdefault. But I am having a problem in encode/decode of the array of this model.
Here is my model Struct
struct Room {
let name : String
let id : String
let booked : Bool
}
Here I created a extension like this
extension Room {
func decode() -> Room? {
let userClassObject = NSKeyedUnarchiver.unarchiveObject(withFile: RoomClass.path()) as? RoomClass
return userClassObject?.room
}
func encode() {
let personClassObject = RoomClass(room: self)
NSKeyedArchiver.archiveRootObject(personClassObject, toFile: RoomClass.path())
}
class RoomClass: NSObject, NSCoding {
var room : Room?
init(room: Room) {
self.room = room
super.init()
}
class func path() -> String {
let documentsPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true).first
let path = documentsPath?.appending(("/Room"))
return path!
}
func encode(with aCoder: NSCoder) {
aCoder.encode(room!.name, forKey: "name")
aCoder.encode(room!.id, forKey: "Id")
aCoder.encode(room!.booked, forKey: "booked")
}
required init?(coder aDecoder: NSCoder) {
let _name = aDecoder.decodeObject(forKey: "name") as? String
let _id = aDecoder.decodeObject(forKey: "Id") as? String
let _booked = aDecoder.decodeBool(forKey: "booked")
room = Room(name: _name!, id: _id!, booked: _booked)
super.init()
}
}
}
When I am trying to save arrRoomList(a Array of Room objects) like this
self.saveRooms(arrayRooms: arrRoomList)
I got this error
[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance
I have also tried to encode each object first and then try to save them in default, then also it gives an error.
Can anyone please guide me how to encode/decode the array of Struct in Userdefaults in a proper way without converting it into Dictionary?
you can setup the struct to use NSKeyedArchiver directly like this:
struct Room {
let name : String
let id : String
let booked : Bool
}
extension Room {
func encode() -> Data {
let data = NSMutableData()
let archiver = NSKeyedArchiver(forWritingWith: data)
archiver.encode(name, forKey: "name")
archiver.encode(id, forKey: "id")
archiver.encode(booked, forKey: "booked")
archiver.finishEncoding()
return data as Data
}
init?(data: Data) {
let unarchiver = NSKeyedUnarchiver(forReadingWith: data)
defer {
unarchiver.finishDecoding()
}
guard let name = unarchiver.decodeObject(forKey: "name") as? String else { return nil }
guard let id = unarchiver.decodeObject(forKey: "id") as? String else { return nil }
booked = unarchiver.decodeBool(forKey: "booked")
self.name = name
self.id = id
}
}
to use with UserDefaults, call like this:
// to encode to data and save to user defaults
let room = Room(name: "asdf", id: "123", booked: true)
UserDefaults.standard.set(room.encode(), forKey: "room")
// to retrieve from user defaults
if let data = UserDefaults.standard.object(forKey: "room") as? Data {
let room = Room(data: data)
}
Can save/retrieve an array of rooms like this:
func saveRooms(arrayRooms: [Room]) {
let roomsData = arrayRooms.map { $0.encode() }
UserDefaults.standard.set(roomsData, forKey: "rooms")
}
func getRooms() -> [Room]? {
guard let roomsData = UserDefaults.standard.object(forKey: "rooms") as? [Data] else { return nil }
return roomsData.flatMap { return Room(data: $0) }
}
// save 2 rooms to user defaults
let roomA = Room(name: "A", id: "123", booked: true)
let roomB = Room(name: "B", id: "asdf", booked: false)
saveRooms(arrayRooms: [roomA, roomB])
// get the rooms
print(getRooms())
You can try Model like
class CardModel: NSObject
{
let name : String
let id : String
let booked : Bool
override init()
{
self.name = ""
self.id = ""
self.booked = false
}
required init(coder aDecoder: NSCoder)
{
self.name = aDecoder.decodeObject(forKey: "name") as! String
self.id = aDecoder.decodeObject(forKey: "id") as! String
self.booked = aDecoder.decodeObject(forKey: "booked") as! Bool
}
func encodeWithCoder(_ aCoder: NSCoder)
{
aCoder.encode(name, forKey: "name")
aCoder.encode(id, forKey: "id")
aCoder.encode(booked, forKey: "booked")
}
}
Use by Creating CardModel model Object
let objCardModel = CardModel()
objCardModel.name = "Shrikant"
objCardModel.id = "8"
objCardModel.booked = true
Access by object
let userName = objCardModel.name

Swift 3 Date type not encoding as part of custom class

I'm having difficulty encoding and decoding a Date type property of a custom Swift class with NSKeyedArchiver. I call the KeyedArchiver with:
let savedData = NSKeyedArchiver.archivedData(withRootObject: timers)
let defaults = UserDefaults.standard
defaults.set(savedData, forKey: "timers")
This is the top half of my class declaration:
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, timerEndTime: Date? = nil) {
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) {
guard let name = decoder.decodeObject(forKey: "name") as? String
else {
print("init coder name guard failed")
return nil
}
let duration = decoder.decodeInteger(forKey: "duration")
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
}
let alarmRepetitions = decoder.decodeInteger(forKey: "alarmRepetitions")
let timerRepetitions = decoder.decodeInteger(forKey: "timerRepetitions")
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
}
var timerEndTimeUnwrapped: Date?
if let timerEndTime = decoder.decodeObject(forKey: "timerEndTime") as? Date {
timerEndTimeUnwrapped = timerEndTime
} else {
timerEndTimeUnwrapped = nil
}
print("initCoder guards passed, initing timer")
print("\(name), \(duration), \(UUID), \(colorScheme), \(audioAlert), \(timerRepetitions), \(alarmRepetitions), \(timerEndTimeUnwrapped)")
self.init(withName: name, duration: duration, UUID: UUID, color: colorScheme, alertNoise: audioAlert, timerRepetitions: timerRepetitions, alarmRepetitions: alarmRepetitions, timerEndTime: timerEndTimeUnwrapped)
}
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")
aCoder.encode(self.timerEndTime, forKey: "timerEndTime")
}
When I try to unarchive the object from NSUserDefaults the timerEndTimeUnwrapped always comes back as nil. Either I've messed up unwrapping the thing or either the encode or decode are failing. Everything else comes back as expected, it's just the date type that is problematic
Any help would be great.
So this is a really stupid mistake, problem with adding properties once a class is being used a lot. I wasn't setting the timerEndTime in the init function of the class!

Thread 1:EXC_BAD_INSTRUCTION error when calling "addObjectsFromArray"method for NSMutableArray

I have created a program where it calculates the borders of certain countries based on a Custom Object being inputed into a function. This function returns an array of custom objects. I keep getting this error when trying to add this array to a NSMutableArray. The error is called "Thread 1: EXC_BAD_INSTRUCTION(code=EXC_1386_INVOP, subcode=0x0)".
Here is my adding code:
#IBOutlet var Label: UILabel!
#IBOutlet var imageView: UIImageView!
override func viewDidLoad() {
//Afganistan
Afghanistan.name = "Afghanistan"
Afghanistan.borders.addObjectsFromArray(relate(Afghanistan))
Label.text = String((Afghanistan.borders[0] as! develop).name)
}
Here is the relate method along with the group dictionary:
func relate(X : develop) -> Array<develop>{
var A : [develop] = []
for (_, value) in groups {
for y in value {
if y.name == X.name {
for i in value {
if i.name != X.name {
A.append(i)
}
}
}
}
}
return A
}
//Groups
var groups = [
"one": [Afghanistan]
]
Here is the class of develop:
class develop : NSObject, NSCoding {
//Shared
var power : Int!
var name : String!
var image : UIImage!
var flag : UIImage!
var militaryName : String!
//Military
var experience : Int!
var OATC : Int!
var navy : Int!
var airforce : Int!
var artillery : Int!
//Geography
var borders : NSMutableArray!
var cities : NSMutableArray!
//Biomes
var biom : NSMutableArray!
var continent : String!
var NSEW : String!
//Encoding Section
required convenience init(coder decoder: NSCoder) {
self.init()
//shared
self.power = decoder.decodeObjectForKey("power") as! Int
self.name = decoder.decodeObjectForKey("name") as! String
self.image = decoder.decodeObjectForKey("image") as! UIImage
self.flag = decoder.decodeObjectForKey("flag") as! UIImage
self.militaryName = decoder.decodeObjectForKey("militaryName") as! String
//Military
self.experience = decoder.decodeObjectForKey("experience") as! Int
self.OATC = decoder.decodeObjectForKey("OATC") as! Int
self.navy = decoder.decodeObjectForKey("navy") as! Int
self.airforce = decoder.decodeObjectForKey("airforce") as! Int
self.artillery = decoder.decodeObjectForKey("artillery") as! Int
//Geography
self.borders = decoder.decodeObjectForKey("borders") as! NSMutableArray
self.cities = decoder.decodeObjectForKey("cities") as! NSMutableArray
self.continent = decoder.decodeObjectForKey("continent") as! String
self.NSEW = decoder.decodeObjectForKey("NSEW") as! String
}
convenience init(
power: Int, name: String, image: UIImage, flag: UIImage,
relations: NSMutableArray, mName: String, experience: Int,
OATC: Int, navy: Int, airforce: Int, artillery: Int,
borders: NSMutableArray, cities: NSMutableArray,
biom: NSMutableArray, continent: String, NSEW: String )
{
self.init()
//shared
self.power = power
self.name = name
self.image = image
self.flag = flag
self.militaryName = mName
//military
self.experience = experience
self.OATC = OATC
self.navy = navy
self.airforce = airforce
self.artillery = artillery
//geography
self.borders = borders
self.cities = cities
self.biom = biom
self.continent = continent
self.NSEW = NSEW
}
func encodeWithCoder(coder: NSCoder) {
//Shared
if let power = power { coder.encodeObject(power, forKey: "power") }
if let name = name { coder.encodeObject(name, forKey: "name") }
if let image = image { coder.encodeObject(image, forKey: "image") }
if let flag = flag { coder.encodeObject(flag, forKey: "flag") }
if let militaryName = militaryName { coder.encodeObject(militaryName, forKey: "militaryName") }
//Military
if let experience = experience { coder.encodeObject(experience, forKey: "experience") }
if let OATC = OATC { coder.encodeObject(OATC, forKey: "OATC") }
if let navy = navy { coder.encodeObject(navy, forKey: "navy") }
if let airforce = airforce { coder.encodeObject(airforce, forKey: "airforce") }
if let artillery = artillery { coder.encodeObject(artillery, forKey: "artillery") }
//geography
if let borders = borders { coder.encodeObject(borders, forKey: "borders") }
if let cities = cities { coder.encodeObject(cities, forKey: "cities") }
if let biom = biom { coder.encodeObject(biom, forKey: "biom") }
if let continent = continent { coder.encodeObject(continent, forKey: "continent") }
if let NSEW = NSEW { coder.encodeObject(NSEW, forKey: "NSEW") }
}
}
"Afghanistan" is a subclass of develop

Resources