Search code examples
iosjsonswiftcore-datadecodable

'self.init' isn't called on all paths before returning from initializer


I'm working with CoreData and JSON parsing with Decodable following this and encountered an error at the end of the initializer saying 'self.init' isn't called on all paths before returning from initializer:

import Foundation
import CoreData

extension CodingUserInfoKey {
    static let managedObjectContext = CodingUserInfoKey(rawValue: "managedObjectContext")!
}

@objc(Task)
public class Task: NSManagedObject, Decodable {
    
    enum CodingKeys: String, CodingKey {
        case diff, title, desc, doc
    }
    
    required convenience public init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[CodingUserInfoKey.managedObjectContext] as? NSManagedObjectContext else {
            print("Decode context error")
            return
        }
        guard let entity = NSEntityDescription.entity(forEntityName: "Task", in: context) else {
            print("Decode entity error")
            return
        }
        self.init(entity: entity, insertInto: context)
        do {
            let container = try decoder.container(keyedBy: CodingKeys.self)
            self.diff = try container.decode(String.self, forKey: .diff)
            self.title = try container.decode(String.self, forKey: .title)
            self.desc = try container.decode(String.self, forKey: .desc)
            self.doc = try container.decode(String.self, forKey: .doc)
        } catch {
            print("Decode key error")
        }
    }
    
}

Am I missing something?


Solution

  • You should probably throw a custom error in guard statements instead of just returning. Also you should remove do-catch from decoder function calls:

    enum ManagedObjectError: Error {
        case decodeContextError
        case decodeEntityError
    }
    
    required convenience public init(from decoder: Decoder) throws {
        guard let context = decoder.userInfo[CodingUserInfoKey.managedObjectContext] as? NSManagedObjectContext else {
            throw ManagedObjectError.decodeContextError
        }
        guard let entity = NSEntityDescription.entity(forEntityName: "Task", in: context) else {
            throw ManagedObjectError.decodeEntityError
        }
        self.init(entity: entity, insertInto: context)
        
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.diff = try container.decode(String.self, forKey: .diff)
        self.title = try container.decode(String.self, forKey: .title)
        self.desc = try container.decode(String.self, forKey: .desc)
        self.doc = try container.decode(String.self, forKey: .doc)
    }