如何使用可编码协议Swift在CoreData中保存自定义类型

时间:2019-02-01 14:25:54

标签: swift core-data codable

我试图保存可编码类型的自定义对象,我可以在其中存储Int16类型。但是对于Coredata中其[NSObject]实体的[Movie]类型,我有一个属性movie属于Transformable类型。

  

错误:没有'decodeIfPresent'候选者产生预期的上下文   结果类型为“ NSObject?”

如何使用可转换类型保存此自定义类型数组

[House[type = big, attributes =
    {
        House.KeyValue[key = door, value = HouseKind[value = black]],
        House.KeyValue[key = window, value = HouseKind[value = white]]
    },
    garden = true,
    flowers = {
        House.KeyValue[key = rose, value = HouseKind[value = red]]
    }
],
House[type = small, attributes =
    {
        House.KeyValue[key = door, value = HouseKind[value = red]],
        House.KeyValue[key = swimmingpool, value = HouseKind[value = true]]
    }
    ]},
    flowers = {
        House.KeyValue[key = rose, value = HouseKind[value = purple]]}
    ]
]
  

电影数组是CoreData中可转换类型的自定义属性

class MovieResults: Results, Codable {

        required convenience public init(from decoder: Decoder) throws  {
            guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.context,
                let managedObjectContext = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext,
                let entity = NSEntityDescription.entity(forEntityName: "Results", in: managedObjectContext) else {
                    fatalError("Failed to retrieve managed object context")
            }

            self.init(entity: entity, insertInto: managedObjectContext)

            let container = try decoder.container(keyedBy: CodingKeys.self)

            self.page = try container.decodeIfPresent(Int16.self, forKey: .page) ?? 0
            self.numberOfResults = try container.decodeIfPresent(Int16.self, forKey: .numberOfResults) ?? 0
            self.numberOfPages = try container.decodeIfPresent(Int16.self, forKey: .numberOfPages) ?? 0
            self.movies = try container.decodeIfPresent([Movie].self, forKey: .movies) ?? nil
        }

        // MARK: - Encodable
        public func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(page, forKey: .page)
            try container.encode(numberOfResults, forKey: .numberOfResults)
            try container.encode(numberOfPages, forKey: .numberOfPages)
            try container.encode(movies, forKey: .movies)
        }

        private enum CodingKeys: String, CodingKey {
            case page
            case numberOfResults = "total_results"
            case numberOfPages = "total_pages"
            case movies = "results"
        }
    }
  

有了它,就可以了。

class Movies: Movie, Codable {
    public func encode(to encoder: Encoder) throws {

    }

    required convenience init(from decoder: Decoder) throws {
        guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.context,
            let managedObjectContext = decoder.userInfo[codingUserInfoKeyManagedObjectContext] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Movie", in: managedObjectContext) else {
                fatalError("Failed to decode User")
        }

        self.init(entity: entity, insertInto: managedObjectContext)

        let container = try decoder.container(keyedBy: CodingKeys.self)

        self.identifier = try container.decodeIfPresent(Int16.self, forKey: .identifier) ?? 0
        self.posterPath = try container.decodeIfPresent(String.self, forKey: .identifier)
        self.backdrop = try container.decodeIfPresent(String.self, forKey: .identifier)
        self.title = try container.decodeIfPresent(String.self, forKey: .identifier)
        self.releaseDate = try container.decodeIfPresent(String.self, forKey: .identifier)
        self.rating = try container.decodeIfPresent(Int16.self, forKey: .rating) ?? 0
        self.overview = try container.decodeIfPresent(String.self, forKey: .identifier)
    }

    enum CodingKeys: String, CodingKey {
        case identifier
        case posterPath = "poster_path"
        case backdrop = "backdrop_path"
        case title
        case releaseDate = "release_date"
        case rating = "vote_average"
        case overview
    }
}
  

我正在继承NSManagedObject类这是正确的方法吗?我试过了   使用扩展名,但会为初始化程序引发错误。?

self.movies = try container.decodeIfPresent([Movies].self, forKey: .movies)! as NSObject
  

初始化器要求'init(from :)'只能由   非最终类定义中的“必需”初始化程序   “ MovieResult”

1 个答案:

答案 0 :(得分:0)

我认为这可以通过更简单的方式来完成。这是您可以尝试的方法。这是MovieResult类[最好以单个名称表示类的名称。

公共类MovieResult:可编码{     public var string变量:字符串     public var intVariable:Int

public init(stringVariable: String, intVariable: Int) {
    self.stringVariable = stringVariable
    self.intVariable = intVariable
}

}

在这里您可以将MovieResult保留在UserDefaults中。

public var savedMovieResult: MovieResult? {
    get {
        let data = UserDefaults.standard.object(forKey: "savedMovieResultKey") as? Data
        var movieResult: MovieResult?
        if let data = data {
            do {
                movieResult = try PropertyListDecoder().decode(MovieResult.self, from: data)
            } catch {
                print(error)
            }
        }
        return movieResult
    } set {
        do {
            try UserDefaults.standard.set(PropertyListEncoder().encode(newValue), forKey: "savedMovieResultKey")
            UserDefaults.standard.synchronize()
        } catch {
            print(error)
        }
    }
}