Class referencing codable protocols is not codable - swift

If a member of my class AnotherClass is a of a type with codable abstract protocol the compiler fails to synthesize the coding/decoding code for the class. If instead the same member is a concrete class conforming to the same protocol then the compiler will happily synthesize the coding/decoding code. I think the second case should work, the property mp will always be a Codable concrete instance of MyProtocol, which is Codable.
/* This works */
protocol MyProtocol : Codable {
func a(_ n : Int) -> Int
}
class MyClass : MyProtocol {
let x = 3
func a( _ n : Int ) -> Int {
return n * x
}
}
class AnotherClass : Codable {
let y = 5
let mp : MyClass // <---- ACTUAL CLASS
init() {
mp = MyClass()
}
}
/* But this won't work.
Compiler error:
Type 'AnotherClass' does not conform to protocol 'Decodable'
Type 'AnotherClass' does not conform to protocol 'Encodable'
*/
protocol MyProtocol : Codable {
func a(_ n : Int) -> Int
}
class MyClass : MyProtocol {
let x = 3
func a( _ n : Int ) -> Int {
return n * x
}
}
class AnotherClass : Codable {
let y = 5
let mp : MyProtocol // <-------- PROTOCOL
init() {
mp = MyClass()
}
}

This is how you fix it.
class AnotherClass<T: MyProtocol> : Codable {
let y = 5
let mp : T
init() {
mp = MyClass() as! T // handle this more gracefully
}
}
And use it this way
let a = AnotherClass<MyClass>()
But please consider reading this answer here. It explains a lot about why protocols behave the way they do and will help you understand more about them.

Related

Copy constructor and "Cannot call value of non-function type" error

I have a base class A and three subclasses:
class A {}
class X : A {}
class Y : A {}
class Z : A {}
In my code, I have an instance m which I would like to create a copy of, of the same type.
I can successfully use the following code:
let n = type(of: m).init(m)
... and in class A:
required init(m : A) {
self.param1 = m.param1
I try to simplify things by creating a copy constructor in class A:
func copy() {
return type(of: self).init(self)
}
but this declaration generates the error: Cannot call value of non-function type 'AType'
Two questions: What am I doing wrong? and Is there a simpler way to create a copy constructor involving subclasses?
Try the Prototype desing pattern:
public protocol Copying: class {
init(_ prototype: Self)
}
extension Copying {
public func copy() -> Self {
return type(of: self).init(self)
}
}
public class A: Copying {
public var value1: Int
public var value2: Int
public init(value1: Int, value2: Int) {
self.value1 = value1
self.value2 = value2
}
public required convenience init(_ a: A) {
self.init(value1: a.value1, value2: a.value2)
}
}
and you can use it like:
let a = A(value1: 700, value2: 37)
let aCopy = a.copy()

Not Able to access values with .Type swift

Why am I not able to assign and read value from Type B in below code? B.self should be passed as a type and not an instance, so it should access static var in class B right?
class A{
}
class B:A{
static var a = 5
}
class c{
static func a(){
b(type: B.self)
}
static func b(type:B.Type){
print(type.a)
}
func takeObject<T>(type:T.Type){
print(type(of:String.self)) // String.Type
print(type) // B
print(type.a) // Value of type 'T' has no member 'a'
var a :type // Use of undeclared type 'type'
}
}
let objects : c = c()
objects.takeObject(object: B.self)
Correct me please, I am new on this topic and it seems quite interesting.
As i think you just want to add objects of type B so you can specify generic T of type B as below,
class A {}
class B: A {
static var a = 5
}
class c {
static func a() {
b(type: B.self)
}
static func b(type: B.Type){
print(type.a)
}
func takeObject<T: B>(type: T.Type){
print(type)
print(type.a)
var a : T
}
}
let objects : c = c()
objects.takeObject(type: B.self)

Swift - How to get class that extended from protocol?

Is there a way that I could get the Class type or Struct type that extended my Protocol?
Here are my sample code:
protocol a {}
extension a {
static func list(completion: ([StructType] -> Void)) {
var items = [StructType]()
...
completion(items)
}
}
struct b{}
extension b: a {}
struct c{}
extension c: a{}
In this case I want to dynamically get the type of struct a and b, so that I could generate a list of it and return.
Thank you in advance for kindly answering my question.
Use the Self keyword
protocol P {
init()
}
extension P {
static func list(completion: ([Self]) -> Void) {
let items = [Self(), Self(), Self()]
print(Self.self)
completion(items)
}
}
struct B {}
extension B: P {}
class C {
required init() {}
}
extension C: P {}
B.list{ print($0) }
C.list{ print($0) }

Using array of protocol in Swift class' generics

Is there any way to use array of protocol's generic?
For example,
/* I want to use protocol like below,
* but I can't because protocol is not concrete
* so cannot make array of it */
class MyClass<T where T:MyProtocol, T:[MyProtocol]> {
let result: T
}
protocol MyProtocol {
init(with: String)
}
class SpecialThing: MyProtocol {
let appleWatch: AppleWatch
init(with: String) {
self.appleWatch = AppleWatch(with)
}
}
class SampleClass {
func test {
typealias listCallback = (MyClass<[SpecialThing]>, NSError) -> ()
typealias oneCallback = (MyClass<SpecialThing>, NSError) -> ()
}
}
There can be one object or array of protocol's subclass.
I think "typealias" does not help me.
I want to find something more simple way.....
My first issue with this is that the type signature is wrong:
class MyClass<T where T:MyProtocol, T:[MyProtocol]>
That's the same type of thing as doing:
let t: String
let t: [String]
t = String("foo")
The compiler will complain because you are redefining T, once as a MyProtocol and again as an array of MyProtocol. You can't have both, you can only have one.
Answer: Use a construct like Either:
enum Either<T, U>
{
case Left(T)
case Right(U)
var leftValue: T?
{
if case .Left(let leftValue) = self
{
return leftValue
}
return nil
}
var rightValue: U?
{
if case .Right(let rightValue) = self
{
return rightValue
}
return nil
}
}
Allowing for:
class MyClass<T: MyProtocol>
{
let result: Either<T, [MyProtocol]>
}

How to construct generic without protocol in Swift?

I'm getting the following error...
'T' cannot be constructed because it has no accessible initializers
When compiling...
class Sub<T : Equitable> {
func def(v : T) -> Bool{
var d = T() // <- Error
return d == v
}
}
var s = Sub<Int>()
println(s.def(0), s.def(1)) // I'm expecting "true, false"
I understand that in order for a generic type to be initialized, it needs to conform to a protocol that contains an init() constructor. Such as...
protocol A : Equitable {
init()
}
class Sub<T : A> {
But then I would get get the error
Type 'Int' does not conform to protocol 'A'
at the line
var s = Sub<Int>()
So how would I go about making a value type such as Int or Bool conform to a protocol that can be initialized?
You need to extend Int like so for it to adopt protocol A:
class Sub<T : A> {
func def(v : T) -> Bool{
var d = T()
return d == v
}
}
protocol A : Equatable {
init()
}
extension Int: A {
}
var s = Sub<Int>()
s.def(0) // true
s.def(1)) // false