Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 在后台线程上保存后,多线程核心数据对象在主线程上的属性为空_Swift_Core Data_Ios10 - Fatal编程技术网

Swift 在后台线程上保存后,多线程核心数据对象在主线程上的属性为空

Swift 在后台线程上保存后,多线程核心数据对象在主线程上的属性为空,swift,core-data,ios10,Swift,Core Data,Ios10,正如标题中简要描述的,在后台线程上保存对象后,其属性在主线程上为空,例如字符串为”,数字为0等 这里有一些代码 用户类别: @objc(User) class User: NSManagedObject { @NSManaged var id: Int32 @NSManaged var email: String } 正在进行实际保存的用户存储库: func saveUser(fromJSON json: Any, onSuccess: ((User) -> Void)

正如标题中简要描述的,在后台线程上保存对象后,其属性在主线程上为空,例如字符串为
,数字为
0

这里有一些代码

用户类别:

@objc(User)
class User: NSManagedObject {

    @NSManaged var id: Int32
    @NSManaged var email: String
}
正在进行实际保存的用户存储库:

func saveUser(fromJSON json: Any, onSuccess: ((User) -> Void)?, onFailure: ((Error) -> Void)?) {
    dataManager.persistentContainer.performBackgroundTask { context in
        context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
        let user = self.userFactory.user(fromJSON: json, inContext: context)
        // print(user.id) and print(user.email) output correct data
        do {
            try context.save()
            DispatchQueue.main.async {
                // print(user.id) and print(user.email) show 0 and ""
                onSuccess?(user)
            }
        } catch let error {
            DispatchQueue.main.async {
                onFailure?(error)
            }
        }
    }
}
其中
dataManager
的配置如下:

class CoreDataManager {

    private let modelName: String

    lazy var persistentContainer: NSPersistentContainer = {
        let container = NSPersistentContainer(name: modelName)
        container.loadPersistentStores(completionHandler: { (storeDescription, error) in
            if let error = error as NSError? {
                fatalError("Unresolved error \(error), \(error.userInfo)")
            }

            container.viewContext.automaticallyMergesChangesFromParent = true
            container.viewContext.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
        })
        return container
    }()

    init(modelName: String) {
        self.modelName = modelName
    }
}
我猜
userFactory
没有那么重要,但为了完整性:

class UserFactory {

    func user(fromJSON json: Any, inContext context: NSManagedObjectContext) -> User {
        guard
            let jsonDictionary = json as? [String: Any?],
            let userDictionary = jsonDictionary["user"] as? [String: Any?],
            let id = userDictionary["id"] as? Int32,
            let email = userDictionary["email"] as? String
        else {
            fatalError("Could not parse User object.")
        }

        let user = User(context: context)
        user.id = id
        user.email = email
        return user
    }
}
请参阅上面代码片段中有关打印语句的注释,这些语句指出了用户属性良好的位置以及它们显示
0
的位置

我知道我无法在线程之间传递NSManagedObjects,但即使我尝试使用
DispatchQueue.main.async
块的
objectID
NSManagedObjectID
)获取用户对象,用户属性仍然为空

我想我做错了什么事,但我一点也不怀疑。如有任何建议,将不胜感激


非常感谢

我认为,问题在于核心数据不是线程安全的。我知道你们知道这一点——毕竟,这就是为什么你们创建了一个特殊的背景环境——但它有非常严格的含义。你是说:

dataManager.persistentContainer.performBackgroundTask { context in
    context.mergePolicy = NSMergePolicy.mergeByPropertyObjectTrump
    let user = self.userFactory.user(fromJSON: json, inContext: context)
    do {
        try context.save()
        DispatchQueue.main.async {
            print(user) // <--
dataManager.persistentContainer.performBackgroundTask{上下文在
context.mergePolicy=NSMergePolicy.mergeByPropertyObject特朗普
让user=self.userFactory.user(fromJSON:json,inContext:context)
做{
尝试context.save()
DispatchQueue.main.async{

打印(用户)//当你说
user.id=id
user.email=email
时,你确认了这些不是
nil
吗?是的,我有-在上面的守卫声明中,在工厂里。哦,是的,我明白了,傻我,对不起。-顺便说一句,我真的很喜欢格式化
守卫
列表的方式。我将在我自己的代码中采用它!谢谢ou,很高兴你喜欢它!是的,我认为当有超过1条语句时,它很容易阅读。请看。它用大写字母写着,“不要在队列之间传递NSManagedObject实例”。但在我看来,这正是你正在做的。谢谢@matt!是的,它实际上需要一个单独的
NSFetchRequest
user.id
(以前存储在一个变量中)。我希望只要转到
privateContext.object(带id:user.objectID)
viewContext.object(带id:user.objectID)就足够了
。如果我存储例如1000个对象,然后必须立即从核心数据中重新查询它们,这似乎不是最佳选择,但我认为这就是它的本质。再次感谢您的时间!干杯:)@imilakovic,我可以知道您如何解决它。我遇到了与我第一次在CoreData中使用bakground上下文相同的问题,我将CoreData中的内容保存在后台上下文中,然后重试推回到主线程以在UI更改时反映它。但是UI(tableView)没有显示任何内容,尽管属性具有该值。