My structure does not conform to protocol 'Decodable' / 'Encodable' - swift

I was trying to use Codable to save my data from the app I am creating but when I put Codable into my structure I keep getting the error:
Type 'ReminderGroups' does not conform to protocol 'Decodable'
and
Type 'ReminderGroups' does not conform to protocol 'Encodable'
struct ReminderGroups: Codable {
var contentsArray: [ReminderItem] = []
var reminderName: String = ""
var reminderItem: UIImage = #imageLiteral(resourceName: "Folder")
}

In order for a class or a struct to conform to a protocol, all properties of that class or struct must conform to the same protocol.
UIImage does not conform to Codable, so any class or struct that has properties of type UIImage won’t conform as well. You can replace the image with image data or the image’s base64 representation (as String).
I’ll show you the first option. I suppose you don’t want to write those if lets every time, so let’s add two little extensions to UIImage and Data that will speed up future conversions.
extension UIImage {
var data: Data? {
if let data = self.jpegData(compressionQuality: 1.0) {
return data
} else {
return nil
}
}
}
extension Data {
var image: UIImage? {
if let image = UIImage(data: self) {
return image
} else {
return nil
}
}
}
Change reminderItem’s type from UIImage to Data.
From now on, when you need to access the image, write something like imageView.image = reminderGroup.reminderItem.image. And when you need to save an instance of UIImage to reminderItem, write something like reminderGroup.reminderItem = image.data! (the bang operator (exclamation mark) is needed because the computed property data is optional).
Also make sure ReminderItem does conform to Codable. You didn’t provide the declaration of that type, so I can’t say whether it conforms of not.

Related

Is there a way to check if a delegate is a value or a reference type?

Lets say we had something like this:
protocol Delegate {}
struct Value: Delegate {}
class Reference: Delegate {}
struct Test {
let delegate: Delegate
}
How could we know if a delegate is a struct (value type) or a class (reference type)?
First thought that comes to mind is to check memory address equality after making a copy of a delegate:
struct Test {
let delegate: Delegate
var isReferenceType: Bool {
let copy = delegate
let copyAddress = // ... get memory address of a copy
let originalAddress = // ... get memory address of an original
return copyAddress == originalAddress
}
}
Is it even possible to do this?
Is there more elegant/correct way of doing this?
Copying a value type might potentially be an expensive operation?
Every class conforms to the AnyClass protocol. However enums and structs won't. Utilising that you can check if it's a class or a struct(or even an enum)
struct Test {
let delegate: Delegate
var isReferenceType: Bool {
return type(of:delegate) is AnyClass
}
}

Swift: List all objects that have the same protocol implemented

Hello in my project I have 3 objects that receive the same protocol, is there a way to list all the classes having the same protocol to print it?
By doing
if let _ = someObject as? SomeProtocol {
///
}
you can check if this object conforms to SomeProtocol.
An array of object can be compactMapped like this
let objectsThatConform = arrayOfObjects.compactMap { $0 as? SomeProtocol }

Can I implement default initialization in protocol in Swift

I have a variety of classes that all conform to a single protocol and share the same initialization method. Is there a way to implement the initialization in the protocol? So I don't have to copy the code in every class. This is what I have so far
protocol someProtocol {
init(data: Data)
}
class ObjectA: someProtocol {
let data: Data
required init(data: Data) {
self.data = data
}
}
class ObjectB: someProtocol {
let data: Data
required init(data: Data) {
self.data = data
}
}
You can’t do this as the protocol and protocol extension have no knowledge about the properties in the objects that conform to them and so you cannot initialise all the story properties.
I’m sure there are other runtime reason about type inference too but this one is probably the most simple to explain.

Change superclass property type on swift

In a super Class called TableViewCell I have a property
class TableViewCell {
var model: AnyObject?
}
In a class called CountryTableViewCell I wrote this code
class CountryTableViewCell : TableViewCell {
var model:[AnyObject]? {
didSet {
// do some stuff
}
}
}
and I got this error
property model with [AnyObject]? cannot override a property with type
Anyobject?
Is it not possible to change the property model to an array?
No, you cannot use like that. Also AnyObject should be replaced by Any if using Swift 3.
You can change your code as below:
class TableViewCell {
var model: Any?
}
class CountryTableViewCell : TableViewCell {
override var model: Any? {
didSet {
}
}
}
Now if you want to get an array of the model in didSet then you can type cast it as below code.
class CountryTableViewCell : TableViewCell {
override var model: Any? {
didSet {
if let arrModel = model as? [Any] {
// Do Stuff...
}
}
}
}
No the property's type cannot be changed. If this is allowed, it would violate type safety by:
let subcell: CountryTableViewCell = CountryTableViewCell()
let supercell: TableViewCell = subcell
supercell.model = "anything that is not an array" as NSString
let wrong = subcell.model // not an array!
#ParthAdroja's answer showed a runtime workaround for this. You won't get an array at compile type, but at least you can ensure you have an array at runtime.
In principle if the property is read-only this specialization in subclass should work (it is same as restricting the return type of a function), but it doesn't work as of Swift 3. Anyone care about this can file an SE request to the Swift team ☺.
(Additionally, Apple do have some magic to make it work with bridged Objective-C classes, but we don't know what it is yet.)

Any ideas on how to have a generic class, implementing a protocol, be cast to that protocol and allow retrieving a property?

I have a simple Result object which should contain an object (class, struct or enum) and a Bool to say whether it was cancelled or not. I need to interrogate this object along its path (before it gets to its destination, where the destination knows what kind of object to expect) to determine whether it was cancelled or not (without worrying about the accompanying object at that moment). My object looks like:
import Foundation
#objc protocol Resultable {
var didCancel: Bool { get }
}
class Result<T>: Resultable {
let didCancel: Bool
let object: T?
init(didCancel: Bool, object: T?) {
self.didCancel = didCancel
self.object = object
}
}
The idea being that my Result object can wrap the didCancel flag and the actual object (which can be of any type), and the fact that it implements the Resultable protocol means that I can interrogate it at any point to see whether it was cancelled by casting it to Resultable.
I understand (while not liking it) that the protocol has to be prefixed with #objc so that we can cast to it (according to the Apple docs). Unfortunately, when I run the code below (in a playground or in a project), I get a nasty "does not implement methodSignatureForSelector:" error message:
let test = Result(didCancel: false, object: NSArray())
println(test.didCancel)
// transform the object into the form it will be received in
let anyTest: AnyObject = test
if let castTest = anyTest as? Resultable {
println(castTest.didCancel)
}
It seems that despite the protocol being prefixed with #objc, it also wants the actual class to inherit from NSObject (and this is not a requirement that Apple makes explicit). This is obviously a problem for a generic class.
Is there anything I am missing here? Any way to get this to work? Failing that, are there any workarounds (although I strongly believe that this kind of thing should be possible - perhaps we can hope that Apple will do away with the #objc protocol casting requirement at some stage)?
UPDATE
It looks like this is solved with Swift 1.2
You can now cast to a non-ObjC protocol, and without the object having to inherit from NSObject.
It seems that despite the protocol being prefixed with #objc, it also wants the actual class to inherit from NSObject
This is not true. For example, the following code works as expected:
#objc protocol MyProtocol {
var flag: Bool { get }
}
class MyClass: MyProtocol {
let flag = true
}
let foo:AnyObject = MyClass()
if let p = foo as? MyProtocol {
println(p.flag)
}
The problems is that: Any methods/properties declared in Swift Generic classes are invisible from Objective-C. Hence, from the perspective of #objc protocol Resultable, didCancel property declared in Result<T> is invisible. That's why methodSignatureForSelector: is called.
The workaround here is very annoying: You have to have non Generic base class for Result that implements didCancel.
#objc protocol Resultable {
var didCancel: Bool { get }
}
class ResultBase: Resultable {
let didCancel: Bool
init(didCancel: Bool) { self.didCancel = didCancel }
}
class Result<T>: ResultBase, Resultable {
// ^^^^^^^^^^^^
// You have to explicitly conforms `Resultable` here as well for some reason :/
let object: T?
init(didCancel: Bool, object: T?) {
self.object = object
super.init(didCancel: didCancel)
}
}
let test = Result(didCancel: false, object: NSArray())
let anyTest: AnyObject = test
if let castTest = anyTest as? Resultable {
println(castTest.didCancel) // -> outputs "false"
}