Codable : does not conform to protocol 'Decodable' - swift

Not able to figure why my class does not conform to Codable
Please not that in my case I do not need to implement the methods encode and decode.
public class LCLAdvantagePlusJackpotCache: Codable {
public let token: String
public let amount: NSNumber
public let member: Bool
public init(token: String, amount: NSNumber, member: Bool) {
self.token = token
self.amount = amount
self.member = member
}
enum CodingKeys: String, CodingKey {
case token, amount, member
}
}

It's because NSNumber is not Codable. Do not use Objective-C types; use Swift types. (That's a general rule; it isn't confined to the Codable situation. But this is a good example of why the rule is a good one!)
Change NSNumber to Int or Double (in both places where it occurs in your code) and all will be well.

Related

How do I access a Swift String enum in Objective-C?

I've got the following swift autogen model, that i can't change
#objcMembers public class Device: NSObject, Codable {
public enum Auth: String, Codable {
case enabled = "ENABLED"
case supported = "SUPPORTED"
case notSupported = "NOT_SUPPORTED"
case bypassed = "BYPASSED"
}
public var auth: Auth
public var brand: String
}
I'm trying to access the enum property in my Objective-C class like this
self.isAuthEnabled = ([Device.auth.rawValue isEqualToString:#"ENABLED"]);
but I keep getting this error, Property 'auth' not found on object of type 'Device' even though I have access to the brand property, I can't access the enum

How to convert one struct to another with same variables Swift (iOS)?

I need help with converting one object to another. Might have searched 10-20 website didn't find any good answer.
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
I did this:
let say I have value UniversityGroupChatItem in variable universityGroupChatItem and my universityGroupChatItem contains is not nil and contains value. I tried this it did not work.
universityJoinChatViewModel = (universityGroupChatItem) as! UniversityJoinChatViewModel
The app crashed.
Then I tried:
map and
compactmap
None worked.
I am not getting how to convert UniversityGroupChatItem struct to UniversityJoinChatViewModel struct.
I do not understand how to convert one struct to another struct both has same number name variables.
You can't force cast one object into another (no matter struct, class, enum ect.) even if they are fully the same inside
You need to implement inits where one object takes fields from another one.
map is function to sequences, if You have only 1 object just init it with another one
Examples:
public struct UniversityJoinChatViewModel {
public let id: Int?
public let name: String?
public init(nameOfModel model : UniversityGroupChatItem?) {
self.id = model?.id;
self.name = model?.name;
}
}
public struct UniversityGroupChatItem: Codable {
public let id: Int?
public let name: String?
public init(id: Int?, name: String?) {
self.id = id
self.name = name
}
}
let universityGroupChatItem = UniversityGroupChatItem(id: 0, name: "name")
let universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)
let groupArray = Array(repeating: universityGroupChatItem, count: 10)
let joinArray = groupArray.map(UniversityJoinChatViewModel.init(nameOfModel:))
In your case, you already have the constructor that can help you to achieve what you want, so instead of trying to cast the object, create a new one:
universityJoinChatViewModel = UniversityJoinChatViewModel(nameOfModel: universityGroupChatItem)

Error Making Entity Relationship Encodable

I'm trying to get a simple NSManagedObject class to conform to Encodable so that I can easily encode it to JSON.
I have an entity named TestObject that has a one to many relationship with an entity named Device.
Everything works fine until I try to encode an NSSet (to many relationship).
import UIKit
import CoreData
import Foundation
#objc(TestObject)
public class TestObject:NSManagedObject,Encodable
{
#nonobjc public class func fetchRequest() -> NSFetchRequest<TestObject> {
return NSFetchRequest<TestObject>(entityName: "TestObject")
}
#NSManaged public var testName: String?
#NSManaged public var devices: NSSet? // of entity type "Device"
enum CodingKeys: String, CodingKey {
case testName
case devices
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy:CodingKeys.self)
try container.encode(testName,forKey:.testName)
try container.encode(devices,forKey:.devices)
}
}
The error I receive from the compiler is
reference to member 'devices' cannot be resolved without a contextual type
try container.encode(devices,forKey:.devices)
What is this compiler telling me and how can I encode my objects along with its relationships?

public OptionSet with private constructor

I have a sample code:
public struct MyOptions: OptionSet {
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
public static let one = MyOptions(rawValue: 1 << 0)
public static let two = MyOptions(rawValue: 1 << 1)
}
In other module I can do:
print(MyOptions.one)
print(MyOptions(rawValue: 10))
How can I do public struct with private constructor and public static properties(like a one, two) to limit manual creation?
You can't. When you conform a type to a protocol, all the required stubs' protection levels must be at least equal to the type's protection level. I'll try to explain why.
Let's say I have a type Foo that I conform to Hashable. I then assign an instance as a Hashable type:
let foo: Hashable = Foo()
Because the instance is of type Hashable, I am guaranteed to have access to the hash(into:) method. But what if I make the method private? At that point you end up with unexpected behavior. Either for some reason I can't access a method that I was guaranteed access to, or I have access to a method that I shouldn't be able to reach. It's a conflict of access levels.
So yeah, what you want to do isn't possible.

Swift: conforming to properties in protocol?

How to confirm to protocols that declares properties of other protocols in Swift?
There is a protocol GKGameModel in which its implementers need to have a properties conforming to a protocol
public protocol GKGameModel {
// ...
public var players: [GKGameModelPlayer]? { get }
public var activePlayer: GKGameModelPlayer? { get }
// ...
}
public protocol GKGameModelPlayer {
// ...
}
Now, suppose I have a class Player and GameModel that conforms to the above protocols
class Player : NSObject, GKGameModelPlayer {
//...
}
class GameModel : NSObject, GKGameModel {
//...
public var players: [Player]?
public var activePlayer: Player?
}
Now the above code doesn't compile and the error messages (among others) were:
protocol requires property 'activePlayer' with type 'GKGameModelPlayer?'; do you want to add a stub?
candidate has non-matching type 'Player?'
However the Player class conforms to protocol GKGameModelPlayer, hence it should confirm just fine. How can I get this to compile?
Strangely Objective-C deals with this just fine – take a look at the FourInARow example code which does something like this.
The protocol requires that the properties be typed exactly as shown. In other words, an array of GKGameModelPlayers and a single optional GKGameModelPlayer?. If your Player type conforms to the protocol, then an array of Players can be passed to the protocol property if casted / typed as [GKGameModelPlayer].
But the requirement here is not, for example, an activePlayer property that has a type that conforms to GKGameModelPlayer, but rather an activePlayer property that references an instance that it typed as / cast as a GKGameModelPlayer.
I.e. this would fix the error:
class GameModel : NSObject, GKGameModel {
//...
public var players: [GKGameModelPlayer]?
public var activePlayer: GKGameModelPlayer?
}
players and activePlayer property has a type that conforms to GKGameModelPlayer. So just change it to GKGameModelPlayer type instead of Player
class GameModel : NSObject, GKGameModel {
//...
public var players: [GKGameModelPlayer]?
public var activePlayer: GKGameModelPlayer?
}