Swift и CoreData с пользовательским классом в качестве трансформируемого объекта

Я пытаюсь использовать пользовательский класс с swift и CoreData в качестве трансформируемого объекта. Я тратил часы, пытаясь понять это, но не могу. Я получаю две ошибки: свойство не может быть помечено @NSManaged, потому что его тип не может быть представлен в Objective-C, и свойство не может быть объявлено общедоступным, потому что его тип использует внутренний тип.
Помощь очень ценится. Благодарю.

У меня есть объект CoreData с именем пользователя. У меня также есть объект с именем Site.
Я не хочу, чтобы объект Site был объектом CoreData, потому что в большинстве случаев, когда я создаю объект Site, я не хочу, чтобы он добавлялся в контекст CoreData.

Ниже вы увидите "primarySite" типа "Site" и "sites", который является массивом типа "Site". Эти две строки дают те же две ошибки, которые я перечислил выше.

Модель данных Модель данных

Пользователь +CoreDataClass

import Foundation
import CoreData

public class User: NSManagedObject {
}

Пользователь +CoreDataProperties

import Foundation
import CoreData

extension User {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<User> {
        return NSFetchRequest<User>(entityName: "User");
    }

    @NSManaged public var firstName: String?
    @NSManaged public var lastName: String?
    @NSManaged public var role: String?
    @NSManaged public var primarySite: Site
    @NSManaged public var sites: [Site]
}

сайт

import UIKit

class Site: NSCoding {
    let identifier: Int32
    let name: String
    let note: String

    init(with values: Dictionary<String,Any>) {
        identifier = Int32(values["identifier"] as! String)!
        name = values["name"] as! String
        note = values["note"] as! String
    }

    required convenience init(coder decoder: NSCoder) {
        var siteValues = [String:Any]()
        siteValues["identifier"] = decoder.decodeObject(forKey: "identifier") as! String
        siteValues["name"] = decoder.decodeObject(forKey: "name") as! String
        siteValues["note"] = decoder.decodeObject(forKey: "note") as!
        self.init(with: siteValues)
    }

     func encode(with coder: NSCoder) {
        coder.encode(String(self.identifier), forKey: "identifier")
        coder.encode(self.name, forKey: "name")
        coder.encode(self.note, forKey: "note")
    }
}

3 ответа

Решение

Я разобрался, как решить обе ошибки.

1) "Свойство нельзя пометить @NSManaged, так как его тип не может быть представлен в Objective-C"
Благодаря ответу @Tom я разрешаю эту ошибку, сделав Site подклассом NSObject.

class Site: NSObject, NSCoding {


2) "Свойство не может быть объявлено публичным, потому что его тип использует внутренний тип"
Я исправляю эту ошибку, добавляя "public" перед классом и функциями кодировщика и декодера.

public class Site: NSObject, NSCoding {
...
public func encode(with coder: NSCoder) {...}
public required convenience init(coder decoder: NSCoder) {...}

Property cannot be marked @NSManaged because its type cannot be represented in Objective-C

Это происходит потому, что Site не наследуется от NSObject, Классы Swift не должны наследоваться от NSObject, но преобразователи Core Data делают. Если вы добавите NSObject, эта ошибка не возникает.

Есть и другие проблемы - ваши init(coder decoder: NSCoder) например, не присваивает значения свойств, но это должно быть легко понять.

Поскольку Site - это пользовательский класс, вы не можете использовать его в качестве типа данных в NSManagedObject.

В моем случае я сделал их тип "Двоичные данные" в вашей модели данных. Таким образом, делая его тип NSData, который является типом данных в цели c.

После этого вы можете разархивировать данные.

Например:

if let sitesArray = NSKeyedUnarchiver.unarchiveObject(with: sites) as? [[String : Any]] {
    //enter your processing code here to convert them to site objects
}
Другие вопросы по тегам