Why am I getting Cannot convert value of type Bool to expected argument type String - swift

Getting several "Cannot convert value of type Bool to expected argument type String" errors. The method for encoding expects a string but it is getting a Bool?
Here is the code. See the attached image for errors.
import Foundation
class Restaurant {
var name = ""
var item = ""
var location = ""
var image = ""
var isVisited = false
var phone = ""
var rating = ""
init(name: String, item: String, location: String, phone: String, image: String, isVisited: Bool) {
self.name = name
self.item = item
self.location = location
self.phone = phone
self.image = image
self.isVisited = isVisited
}
class func makeNewsItem(_ notificationDictionary: [String: AnyObject]) -> Restaurant? {
if let name = notificationDictionary["name"] as? String,
let phone = notificationDictionary["phone"] as? String,
let location = notificationDictionary["location"] as? String {
let date = Date()
let image = ""
let visited = false
let item = ""
let newsItem = Restaurant(name: name, item: item, location: location, phone: phone, image: image, isVisited: visited)
NotificationCenter.default.post(name: Notification.Name(rawValue: RestaurantTableViewController.RefreshNewsFeedNotification), object: self)
return newsItem
}
return nil
}
}
extension Restaurant: NSCoding {
struct CodingKeys {
static var Name = "name"
static var Item = "item"
static var Location = "location"
static var Image = "image"
static var IsVisited:Bool = false
static var Phone = "phone"
static var Rating = "rating"
}
convenience init?(coder aDecoder: NSCoder) {
if let name = aDecoder.decodeObject(forKey: CodingKeys.Name) as? String,
let location = aDecoder.decodeObject(forKey: CodingKeys.Location) as? Date,
let phone = aDecoder.decodeObject(forKey: CodingKeys.Phone) as? String {
let date = Date()
let image = aDecoder.decodeObject(forKey: CodingKeys.Image) as? String
let visited:Bool = aDecoder.decodeBool(forKey: CodingKeys.IsVisited) as? String
let item = aDecoder.decodeObject(forKey: CodingKeys.Item) as? String
self.init(name: name, item: item, location: location, phone: phone, image: image, isVisited: visited)
} else {
return nil
}
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: CodingKeys.Name)
aCoder.encode(location, forKey: CodingKeys.Location)
aCoder.encode(phone, forKey: CodingKeys.Phone)
aCoder.encode(item, forKey: CodingKeys.Item)
aCoder.encode(image, forKey: CodingKeys.Image)
aCoder.encode(isVisited, forKey: CodingKeys.IsVisited)
aCoder.encode(rating, forKey: CodingKeys.Rating)
}
}

You canĀ“t add a bool value to the forKey. This has to be a string value, so change it from:
aCoder.encode(isVisited, forKey: CodingKeys.IsVisited)
To:
aCoder.encode(isVisited, forKey: "IsVisited")
Same for:
let visited:Bool = aDecoder.decodeBool(forKey: CodingKeys.IsVisited) as? String
To:
let visited:Bool = aDecoder.decodeBool(forKey: "IsVisited") // note, no need for as? String here

Related

how to access an NSObject variable from a structure in swift

I have structure that consists of an a few variables.
struct Contact {
var id:String = "Contact - \(UUID())"
var fullname: String
var exercises : [Exercise]
}
The part i am interest in is the exercises section. This variable takes the following class:
class Exercise : NSObject , NSSecureCoding{
static var supportsSecureCoding: Bool = true
var excerciseName: String
var excerciseReps: String
var excerciseSets: String
var excerciseWeights: String
init(Name : String, Reps : String, Sets : String, Weights : String) {
excerciseName = Name
excerciseReps = Reps
excerciseSets = Sets
excerciseWeights = Weights
}
func encode(with aCoder: NSCoder) {
aCoder.encode(excerciseName, forKey: "excerciseName")
aCoder.encode(excerciseReps, forKey: "excerciseReps")
aCoder.encode(excerciseSets, forKey: "excerciseSets")
aCoder.encode(excerciseWeights, forKey: "excerciseWeights")
}
required convenience init?(coder aDecoder: NSCoder) {
let excerciseName = aDecoder.decodeObject(forKey: "excerciseName") as! String
let excerciseReps = aDecoder.decodeObject(forKey: "excerciseReps") as! String
let excerciseSets = aDecoder.decodeObject(forKey: "excerciseSets") as! String
let excerciseWeights = aDecoder.decodeObject(forKey: "excerciseWeights") as! String
self.init(Name: excerciseName, Reps: excerciseReps, Sets: excerciseSets, Weights: excerciseWeights)
}
}
In the view controller i want to access these variables in i have activated it:
var contacts = [Contact]()
My problem is when i am trying to access it it doesn't give me the option. when i type self.contacts. then nothing appears. i was expecting self.contacts.excercises to be there on auto fill. it that option isn't there. what am i missing?

Cannot convert value of type 'String.Type' to expected argument type 'String'

Swift 4 / Xcode 9.3 / OS X 10.13.4 / iOS 11.3 & 11.2.6
I'm trying to build my app and I'm getting the above error message. I've checked the code over and over and over and I can't figure out why I'm getting this error. I'm not certain which part of the code you need to see, but here is the page I'm getting the error on. The error code is flagging the very last line of code.
import UIKit
import os.log
class Bonus: NSObject, NSCoding {
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("bonuses")
//MARK: Properties
var bonusCode: String
var category: String
var name: String
var value: Int
var city: String
var state: String
var photo: UIImage?
//MARK: Initialization
init?(bonusCode: String, category: String, name: String, value: Int, city: String, state: String, photo: UIImage?) {
// The name must not be empty.
guard !name.isEmpty else {
return nil
}
// The value must not be negative.
guard (value >= 0) else {
return nil
}
// Initialize stored properties.
self.bonusCode = bonusCode
self.category = category
self.name = name
self.value = value
self.city = city
self.state = state
self.photo = photo
}
//MARK: Types
struct PropertyKey {
static let bonusCode = "bonusCode"
static let category = "category"
static let name = "name"
static let value = "value"
static let city = "city"
static let state = "state"
static let photo = "photo"
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(bonusCode, forKey: PropertyKey.bonusCode)
aCoder.encode(category, forKey: PropertyKey.category)
aCoder.encode(name, forKey: PropertyKey.name)
aCoder.encode(value, forKey: PropertyKey.value)
aCoder.encode(city, forKey: PropertyKey.city)
aCoder.encode(state, forKey: PropertyKey.state)
aCoder.encode(photo, forKey: PropertyKey.photo)
}
required convenience init?(coder aDecoder: NSCoder) {
// The name is required. If we cannot decode a name string, the initializer should fail.
guard let bonusCode = aDecoder.decodeObject(forKey: PropertyKey.bonusCode) as? String else {
os_log("Unable to decode the Code for a Bonus object.", log: OSLog.default, type: .debug)
return nil
}
// Because photo is an optional property of Meal, just use conditional cast
let photo = aDecoder.decodeObject(forKey: PropertyKey.photo) as? UIImage
let category = aDecoder.decodeObject(forKey: PropertyKey.category)
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city)
let state = aDecoder.decodeObject(forKey: PropertyKey.state)
// Must call designated initializer.
self.init(bonusCode: String, category: String, name: String, value: Int, city: String, state: String, photo: UIImage?)
}
}
The error is flagging on the bonusCode: String, specifically on the S in String.
I'm pretty new to programming, but I only found one other search result for this specific question, and the other similar ones seemed to be very specific to the code being used.
You have to pass the decoded values rather than the types in the last line and the line to decode the name is missing and you have to cast the other string objects. The force unwrapping is safe because all non-optional values are encoded properly.
let name = aDecoder.decodeObject(forKey: PropertyKey.name) as! String
let category = aDecoder.decodeObject(forKey: PropertyKey.category) as! String
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city) as! String
let state = aDecoder.decodeObject(forKey: PropertyKey.state) as! String
...
self.init(bonusCode: bonusCode, category: category, name: name, value: value, city: city, state: state, photo: photo)
self.init(bonusCode: String,
category: String,
name: String,
value: Int,
city: String,
state: String,
photo: UIImage?)
This is a function call, not a function declaration.
You are passing types instead of values into a function call.
You should be doing this instead:
self.init(bonusCode: bonusCode,
category: category,
name: name,
value: value,
city: city,
state: state,
photo: photo)
So finally, your init should look like (with a little improvement):
required convenience init?(coder aDecoder: NSCoder) {
//NOTE: `decodeObject(forKey:)` returns optional `Any` and hence all those `as? String`
//name was missing
let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String
let bonusCode = aDecoder.decodeObject(forKey: PropertyKey.bonusCode) as? String
let category = aDecoder.decodeObject(forKey: PropertyKey.category) as? String
let value = aDecoder.decodeInteger(forKey: PropertyKey.value)
let city = aDecoder.decodeObject(forKey: PropertyKey.city) as? String
let state = aDecoder.decodeObject(forKey: PropertyKey.state) as? String
let photo = aDecoder.decodeObject(forKey: PropertyKey.photo) as? UIImage
/*
Only photo is optional in order to init but the rest are required
Hence the optional binding for the rest below
*/
if let name = name,
let bonusCode = bonusCode,
let category = category,
let city = city,
let state = state {
// Must call designated initializer.
self.init(bonusCode: bonusCode,
category: category,
name: name,
value: value,
city: city,
state: state,
photo: photo)
}
else {
/*
Some required object/s were missing so we can't call the
designated initializer unless we want to give default values.
Hence return nil
*/
return nil
}
}

Back4app - Swift - Cast PFObject to Class

I am trying to cast a PFObject to a custom class in Swift and I read a lot of post about it and in all of then I need to inherit my class from PFObject. The problem is that my class is already inherited from NSObject and there is a conflict between then.
Is there another way to cast a PFObject to a custom class?
Usuario.swift
class Usuario: NSObject, NSCoding {
//MARK: Propriedades
var nome: String?
var foto: String?
var dataNascimento: Date?
var numeroTelefone: String?
var pais: PaisCodigo?
var telefoneE164: String?
var objectId: String?
var created: Date?
var updated: Date?
override init() {}
required init(coder aDecoder: NSCoder) {
nome = aDecoder.decodeObject(forKey: "nome") as? String
foto = aDecoder.decodeObject(forKey: "foto") as? String
dataNascimento = aDecoder.decodeObject(forKey: "dataNascimento") as? Date
numeroTelefone = aDecoder.decodeObject(forKey: "numeroTelefone") as? String
pais = aDecoder.decodeObject(forKey: "pais") as? PaisCodigo
telefoneE164 = aDecoder.decodeObject(forKey: "telefoneE164") as? String
objectId = aDecoder.decodeObject(forKey: "objectId") as? String
created = aDecoder.decodeObject(forKey: "created") as? Date
updated = aDecoder.decodeObject(forKey: "updated") as? Date
}
func encode(with aCoder: NSCoder) {
if let nomeUsuario = nome {
aCoder.encode(nomeUsuario, forKey: "nome")
}
if let fotoUsuario = foto {
aCoder.encode(fotoUsuario, forKey: "foto")
}
if let dataNascimentoUsuario = dataNascimento {
aCoder.encode(dataNascimentoUsuario, forKey: "dataNascimento")
}
if let numeroTelefoneUsuario = numeroTelefone {
aCoder.encode(numeroTelefoneUsuario, forKey: "numeroTelefone")
}
if let paisUsuario = pais {
aCoder.encode(paisUsuario, forKey: "pais")
}
if let telefoneE164Usuario = telefoneE164 {
aCoder.encode(telefoneE164Usuario, forKey: "telefoneE164")
}
if let objectIdUsuario = objectId {
aCoder.encode(objectIdUsuario, forKey: "objectId")
}
if let createdUsuario = created {
aCoder.encode(createdUsuario, forKey: "created")
}
if let updatedUsuario = updated {
aCoder.encode(updatedUsuario, forKey: "updated")
}
}
}
The Parse result using an objectId returns me this result:
<Usuario: 0x6080000abb20, objectId: 7NwpmD81w3, localId: (null)> {
nome = "Pablo Cavalcante";
numeroTelefone = 67992497386;
pais = "<PaisCodigo: 0x6080000abb80, objectId: rA5wdIWEFt, localId: (null)>";
telefoneE164 = "+5567992497386"; }
So it returns an Usuario object and I need to cast it.
You can use PFSubclassing. I see that you're declaring a user class so you could just subclass PFUser and then write something like this:
class User: PFUser, PFSubclassing {
//MARK: Propriedades
dynamic var nome: String?
dynamic var foto: String?
dynamic var dataNascimento: Date?
dynamic var numeroTelefone: String?
dynamic var pais: PaisCodigo?
dynamic var telefoneE164: String?
dynamic var objectId: String?
dynamic var created: Date?
dynamic var updated: Date?
}
Of course if you're using the init(with:) and encode(with:) you have to implement it...

NSKeyedUnarchiver can't decode some of my keys

I have some keys I want to decode, but it only decodes my first string and then it gives error.
class Profile: NSCoder, NSCoding {
struct Constants {
// Age
static let minimumAge: Int = 5
static let maximumAge: Int = 120
static let defaultAge: Int = 25
// Gender
static let defaultGender: Int = 0
// Daily meals
static let defaultDailyMeals: Int = 3
static let minimumDailyMeals: Int = 1
static let maximumDailyMeals: Int = 10
// Do you train
static let defaultIsTraining: Bool = false
}
//MARK: Properties
private var name: String
private var age: Int
private var gender: Int
private var target: Int
private var dailyMeals: Int
private var isTraining: Bool
private var trainingWhen: Int?
private var trainingDays: [(Int)];
//MARK: Archiving Paths
static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
static let ArchiveURL = DocumentsDirectory.appendingPathComponent("profile")
//MARK: Types
struct PropertyKey {
static let name = "profileName"
static let age = "profileAge"
static let gender = "profileGender"
static let target = "profileTarget"
static let dailyMeals = "profileDailyMeals"
static let isTraining = "profileIsTraining"
static let trainingWhen = "profileTrainingWhen"
static let trainingDays = "trainingDays"
}
// Main init
init?(name: String, age: Int, gender: Int, target: Int, dailyMeals: Int, isTraining: Bool, trainingWhen: Int?, trainingDays: [(Int)]) {
guard !name.isEmpty else {
print("Name empty")
return nil
}
guard age > Constants.minimumAge && age < Constants.maximumAge else {
print("Age not in range")
return nil
}
self.name = name
self.age = age
self.gender = gender
self.target = target
self.dailyMeals = dailyMeals
self.isTraining = isTraining
self.trainingWhen = trainingWhen
self.trainingDays = trainingDays
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(self.name, forKey: PropertyKey.name)
aCoder.encode(self.age, forKey: PropertyKey.age)
aCoder.encode(self.gender, forKey: PropertyKey.gender)
aCoder.encode(self.target, forKey: PropertyKey.target)
aCoder.encode(self.dailyMeals, forKey: PropertyKey.dailyMeals)
aCoder.encode(self.isTraining, forKey: PropertyKey.isTraining)
aCoder.encode(self.trainingWhen, forKey: PropertyKey.trainingWhen)
aCoder.encode(self.trainingDays, forKey: PropertyKey.trainingDays)
}
func dump_data(){
print("Name: " + self.name)
print("Age: " + String(self.age))
print("Gender: " + String(self.gender))
print("Target: " + String(self.target))
print("Daily Meals: " + String(self.dailyMeals))
print("Does train?: " + String(self.isTraining))
print("When: " + String(describing: self.trainingWhen))
print("Days: " + String(describing: self.trainingDays))
}
required convenience init?(coder aDecoder: NSCoder) {
guard let name = aDecoder.decodeObject(forKey: PropertyKey.name) as? String else {
print("Unable to decode the name for a Profile object.")
return nil
}
print("Decoded: Name - \(name)")
guard let age = aDecoder.decodeObject(forKey: PropertyKey.age) as? Int else {
print("Unable to decode the age for a Profile object.")
return nil
}
guard let gender = aDecoder.decodeObject(forKey: PropertyKey.gender) as? Int else {
print("Unable to decode the gender for a Profile object.")
return nil
}
guard let target = aDecoder.decodeObject(forKey: PropertyKey.target) as? Int else {
print("Unable to decode the target for a Profile object.")
return nil
}
guard let dailyMeals = aDecoder.decodeObject(forKey: PropertyKey.dailyMeals) as? Int else {
print("Unable to decode the daily meals for a Profile object.")
return nil
}
guard let isTraining = aDecoder.decodeObject(forKey: PropertyKey.isTraining) as? Bool else {
print("Unable to decode the training state for a Profile object.")
return nil
}
let trainingWhen: Int? = aDecoder.decodeObject(forKey: PropertyKey.trainingWhen) as? Int ?? nil
let trainingDays: [(Int)] = aDecoder.decodeObject(forKey: PropertyKey.trainingDays) as? [(Int)] ?? []
// Must call designated initializer.
self.init(name: name, age: age, gender: gender, target: target, dailyMeals: dailyMeals, isTraining: isTraining, trainingWhen: trainingWhen, trainingDays: trainingDays)
}
The error message I get is
Unable to decode the age for a Profile object.
As long as I know this means that my aDecoder.decodeObject(forKey: PropertyKey.gender) as? Int returns nil and I have completely no idea why this happens, because I encode it as you can see in the code. :/
You should probably use the decodeInteger(forKey:_) method, like this:
self.age = aDecoder.decodeInteger(forKey: PropertyKey.age)
With that said, what I usually do in these cases (considering you only need one instance of the class) is this:
//: Playground - noun: a place where people can play
import UIKit
class Profile: NSCoder, NSCoding {
struct Constants {
// Age
static let minimumAge: Int = 5
static let maximumAge: Int = 120
static let defaultAge: Int = 25
// Gender
static let defaultGender: Int = 0
// Daily meals
static let defaultDailyMeals: Int = 3
static let minimumDailyMeals: Int = 1
static let maximumDailyMeals: Int = 10
// Do you train
static let defaultIsTraining: Bool = false
}
//MARK: Properties
var name: String = ""
var age: Int = 0
var gender: Int = 0
var target: Int = 0
var dailyMeals: Int = 0
var isTraining: Bool = false
var trainingWhen: Int? = nil
var trainingDays = [Int]();
//MARK: Archiving Paths
static let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].path
static let fileName = "profile"
static let path = "\(Profile.documentsDirectory)/\(fileName)"
//MARK: Types
struct PropertyKey {
static let name = "profileName"
static let age = "profileAge"
static let gender = "profileGender"
static let target = "profileTarget"
static let dailyMeals = "profileDailyMeals"
static let isTraining = "profileIsTraining"
static let trainingWhen = "profileTrainingWhen"
static let trainingDays = "trainingDays"
}
// Main init
static var shared = Profile()
fileprivate override init() { }
//MARK: NSCoding
func encode(with archiver: NSCoder) {
archiver.encode(self.name, forKey: PropertyKey.name)
archiver.encode(self.age, forKey: PropertyKey.age)
archiver.encode(self.gender, forKey: PropertyKey.gender)
archiver.encode(self.target, forKey: PropertyKey.target)
archiver.encode(self.dailyMeals, forKey: PropertyKey.dailyMeals)
archiver.encode(self.isTraining, forKey: PropertyKey.isTraining)
archiver.encode(self.trainingWhen, forKey: PropertyKey.trainingWhen)
archiver.encode(self.trainingDays, forKey: PropertyKey.trainingDays)
}
override var description: String {
return """
Name: \(self.name)
Age: \(self.age)
Gender: \(self.gender)
Target: \(self.target)
Daily Meals: \(self.dailyMeals)
Does train?: \(self.isTraining)
When: \(self.trainingWhen ?? 0)
Days: \(self.trainingDays)
"""
}
func save() -> Bool {
return NSKeyedArchiver.archiveRootObject(self, toFile: Profile.path)
}
required init(coder unarchiver: NSCoder) {
super.init()
if let name = unarchiver.decodeObject(forKey: PropertyKey.name) as? String {
self.name = name
}
self.age = unarchiver.decodeInteger(forKey: PropertyKey.age)
self.gender = unarchiver.decodeInteger(forKey: PropertyKey.gender)
self.target = unarchiver.decodeInteger(forKey: PropertyKey.target)
self.dailyMeals = unarchiver.decodeInteger(forKey: PropertyKey.dailyMeals)
self.isTraining = unarchiver.decodeBool(forKey: PropertyKey.isTraining)
if let trainingWhen = unarchiver.decodeObject(forKey: PropertyKey.trainingWhen) as? Int {
self.trainingWhen = trainingWhen
}
if let trainingDays = unarchiver.decodeObject(forKey: PropertyKey.trainingDays) as? [Int] {
self.trainingDays = trainingDays
}
}
}
// TEST:
Profile.shared.name = "Daniel"
Profile.shared.age = 10
Profile.shared.gender = 30
Profile.shared.target = 10
Profile.shared.dailyMeals = 90
Profile.shared.isTraining = true
Profile.shared.trainingWhen = 20
Profile.shared.trainingDays = [1,2,5]
Profile.shared.save()
if let profile = NSKeyedUnarchiver.unarchiveObject(withFile: Profile.path) as? Profile {
print(profile.description)
}
/*
Output:
--------
Name: Daniel
Age: 10
Gender: 30
Target: 10
Daily Meals: 90
Does train?: true
When: 20
Days: [1, 2, 5]
*/

Swift 3 optional parameters

Is it possible to create optional initialization parameters in Swift so I can create an object from JSON with the values returned from the API call, but then when I'm saving that object later I can also save the downloaded UIImage for one of the urls I got before.
Example:
class Story: NSObject, NSCoding {
var id: Int?
var title, coverImageURL: String?
var coverImage: UIImage?
required init?(anId: Int?, aTitle: String?, aCoverImageURL: String?) {
self.id = anId
self.title = aTitle
self.coverImageURL = aCoverImageURL
}
convenience init?(json: [String: Any]) {
let id = json["id"] as? Int
let title = json["title"] as? String
let coverImageURL = json["cover_image"] as? String
self.init(
anId: id,
aTitle: title,
aCoverImageURL: coverImageURL,
)
}
Then Later I want to save objects to memory
//MARK: Types
struct PropertyKey {
static let id = "id"
static let title = "title"
static let coverImageURL = "coverImageURL"
static let coverImage = "coverImage"
}
//MARK: NSCoding
func encode(with aCoder: NSCoder) {
aCoder.encode(id, forKey: PropertyKey.id)
aCoder.encode(title, forKey: PropertyKey.title)
aCoder.encode(coverImageURL, forKey: PropertyKey.coverImageURL)
aCoder.encode(coverImage, forKey: PropertyKey.coverImage)
}
required convenience init?(coder aDecoder: NSCoder) {
guard let id = aDecoder.decodeObject(forKey: PropertyKey.id) as? Int else {
os_log("Unable to decode the id for a Story object.", log: OSLog.default, type: .debug)
return nil
}
guard let title = aDecoder.decodeObject(forKey: PropertyKey.title) as? String else {
os_log("Unable to decode the title for a Story object.", log: OSLog.default, type: .debug)
return nil
}
let coverImageURL = aDecoder.decodeObject(forKey: PropertyKey.coverImageURL) as? String
let coverImage = aDecoder.decodeObject(forKey: PropertyKey.coverImage) as? UIImage
self.init(
anId: id,
aTitle: title,
aCoverImageURL: coverImageURL,
coverImage: coverImage,
)
}
Does this make sense? I want to be able to save a Story object as soon as I get the response from the API, but later when I save the story to memory, I want to be able to save the fetched UIImage for the coverImage.
How would I do that?
I'm not sure why no one took the easy points on this answer, but the answer is to simply make your properties optionals, and then you can set them with a value, or nil. You can also create convenience initializers that automatically set certain values to nil if you want. So, using my app as an example, I have a model that gets built from an API call. that model has values like id, created_at, etc that don't exist until a record is saved to the server, but I create objects locally, store them, and eventually send them to the server, so I need to be able to set the above values only when creating an object from JSON, so here is what I did:
class Story: NSObject, NSCoding {
var id: Int?
var title, coverImageURL: String?
var coverImage: UIImage?
required init?(anId: Int?, aTitle: String?, aCoverImageURL: String?) {
self.id = anId
self.title = aTitle
self.coverImageURL = aCoverImageURL
}
convenience init?(json: [String: Any]) {
let id = json["id"] as? Int
let title = json["title"] as? String
let coverImageURL = json["cover_image"] as? String
self.init(
anId: id,
aTitle: title,
aCoverImageURL: coverImageURL,
)
}
convenience init?(aTitle: String, aCoverImage: UIImage?) {
let title = aTitle
let subtitle = aSubtitle
let coverImage = aCoverImage
let isActive = activeStatus
self.init(
anId: nil,
aTitle: title,
aCoverImageURL: nil,
aCoverImage: coverImage,
)
}
As you can see, I only set two of the values when I'm creating an object locally, and the other values are just set to nil. To allow a value to be set to nil, just make it an optional when setting it. Simple!