I am having an issue with objects seemingly not conforming to the Equatable
protocol after being loaded from a plist. Some background: I have an object TransmitterList
type that holds an array of type Transmitters. On first start up everything works as it should and I am able to delete items by calling
if let index = transmitterList.transmitters.firstIndex(of: transmitter) {
transmitterList.transmitters.remove(at: index)
}
This method works perfectly on the first run, the issue comes after the app data has been saved and reloaded after terminating the app. All saving and loading is done using the Codable
Protocol and Plist encoders and decoders. The transmitters in the transmitterList are still there but when trying to delete a transmitter the call to firstIndex(of:)
returns nil
. Other methods that rely on the Equatable
protocol also do not function correctly. It seems as if the transmitters that got saved no longer conform to Equatable
. However, when adding new transmitters after restarting I am able to successfully delete any newly added transmitters.
I was able to create a work around by comparing some of the transmitters attributes and removing them that way but it doesnt seem very robust. Really want to understand what the underlying cause could be for the transmitters to no longer be conforming to Equatable
.
Any help is appreciated, thank you!!
Updated with saving and loading code.
This is the dataModel object I am using which simply saves an array of TransmitterLists. There is no custom encoding or decoding in the Transmitter class, it simply conforms to Codable
without any additional methods.
class DataModel {
// MARK: - Properties
var transmitterLists = [TransmitterList]()
// MARK: - Initialization
init() {
loadData()
}
// MARK: - Data Persistence
func documentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask)
return paths[0]
}
func dataFilePath() -> URL {
return documentsDirectory().appendingPathComponent("FrequencyCoordinator.plist")
}
func saveData() {
let encoder = PropertyListEncoder()
do {
let data = try encoder.encode(transmitterLists)
try data.write(to: dataFilePath(), options: Data.WritingOptions.atomic)
print("DATA SAVED!!")
} catch {
print("That did not work: \(error.localizedDescription)")
}
}
func loadData() {
let path = dataFilePath()
if let data = try? Data(contentsOf: path) {
let decoder = PropertyListDecoder()
do {
print("DATA LOADED")
transmitterLists = try decoder.decode([TransmitterList].self, from: data)
} catch {
print("That didnt work ;-< \(error.localizedDescription)")
}
}
}
}
Adding in the Transmitter class. Any additional types also conform to Codable
but only by declaring in the definition. Perhaps there is more work to be done in making sure types conform correctly?
class Transmitter: Equatable, Codable {
static func == (lhs: Transmitter, rhs: Transmitter) -> Bool {
return lhs.id == rhs.id
}
var id: Int
var name: String
var transmitterType: TransmitterType
var block: Block
var frequency: Frequency
var doesOverlap: Bool = false
var transmitterOverlapRange: ClosedRange<Double>
var imProductOverlapRanges = [ClosedRange<Double>]()
var overlapsWith = [Transmitter]()
var doesHaveTwoTransmitterIMInterference = false
var doesHaveThreeTransmitterIMInterference = false
var twoTransmitterIMProductsOverlap = [TwoTransmitterIMProduct]()
var threeTransmitterIMProductsOverlap = [ThreeTransmitterIMProduct]()
var isDisabled = false
var frequencyIsSet: Bool {
get {
self.frequency.literal != 0.0
}
}
init(name: String, type: TransmitterType, block: Block, frequency: Frequency, transmitterOverlapRange: ClosedRange<Double>) {
self.id = DataModel.nextTransmitterID()
self.name = name
self.transmitterType = type
self.block = block
self.frequency = frequency
self.transmitterOverlapRange = transmitterOverlapRange
}
enum TransmitterType: Int, Codable {
case talent
case hops
case ifb
}
}
.init(decoder:)
andencode(encoder:)
methods for transmitter objects? If so can you post them, as I suspect you are not decoding the same as you are encoding. – flanker