Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.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 NSManagedObject子类在10.13及以下版本中错误地添加了模块名称 上下文_Swift_Cocoa_Core Data_Nsmanagedobject - Fatal编程技术网

Swift NSManagedObject子类在10.13及以下版本中错误地添加了模块名称 上下文

Swift NSManagedObject子类在10.13及以下版本中错误地添加了模块名称 上下文,swift,cocoa,core-data,nsmanagedobject,Swift,Cocoa,Core Data,Nsmanagedobject,我正在使用Xcode 12在macOS Catalina(10.15.6)上构建一个应用程序。该应用程序使用核心数据。我已经让Xcode使用Swift生成了NSManagedObject实体的子类。这些看起来像这样: // LPProject+CoreDataClass.swift import Foundation import CoreData @objc(LPProject) public class LPProject: NSManagedObject { @objc fun

我正在使用Xcode 12在macOS Catalina(10.15.6)上构建一个应用程序。该应用程序使用核心数据。我已经让Xcode使用Swift生成了NSManagedObject实体的子类。这些看起来像这样:

// LPProject+CoreDataClass.swift

import Foundation
import CoreData

@objc(LPProject)
public class LPProject: NSManagedObject
{
    @objc func printStuff() {
        NSLog("This is a function to test the situation.")
    }
}

和另一个自动生成的文件:

// LPProject+CoreDataProperties.swift

import Foundation
import CoreData

extension LPProject {

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

}
在macOS 10.14.6和10.15上,这一点非常有效。在旧版本上,它会产生“无法识别的选择器”崩溃:

发生这种情况是因为模块名在类名前面。我看到这个日志消息:

warning: Unable to load class named 'MyApp.LPProject' for entity 'LPProject'.
Class not found, using default NSManagedObject instead.
根据我能找到的所有信息,在Core Data editor中正确配置了实体以使用
@objc()
声明:


那么…我错过了什么?为什么在10.14.5及以下版本的类名前面加了模块名,而在10.14.6+版本中没有加模块名?

我尝试了很多方法,包括基于其他SO答案的方法:

  • 删除
    @obc(LPProject)
    属性,改用
    @objc LPProject
    。这修复了macOS 10.11->10.13,但破坏了10.14和10.15上的轻量级迁移

  • 删除Xcode模型编辑器中所有实体的“模块”,并允许核心数据使用全局名称空间。这打破了现代macOS,违反了苹果公司的最新准则


  • 要点 macOS 10.14.6+上的核心数据解析
    MyApp.LPProject
    以查找类
    LPProject
    ,从而实例化正确的NSManagedObject子类。但是,在较旧的macOS版本上,核心数据无法连接这两个对象,因此它没有实例化
    LPProject
    对象,而是返回到通用
    NSManagedObject
    对象

    因此,在macOS 10.14.5及以下版本中,我们必须告诉核心数据名为“LPProject”的实体的该死类名是
    LPProject
    ,而不是
    MyApp.LPProject
    。我们必须对模型中的每个实体重复这一点。为此,我们可以劫持模型加载点:

    - (NSManagedObjectModel *) managedObjectModel 
    {
        if (_managedObjectModel) {
            return _managedObjectModel;
        }
        
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"myDataFile" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        
        if (@available(macOS 10.14.6, *))
        {
            // Do nothing; not needed
        }
        else
        {
            NSArray<NSEntityDescription*> *entities = [_managedObjectModel entities];
            NSMutableArray *fixedEntities = [NSMutableArray arrayWithCapacity:entities.count];
    
            for (NSEntityDescription *des in entities)
            {
                if ([des.managedObjectClassName hasPrefix:@"MyApp."] && des.managedObjectClassName.length > 6) 
                {
                    NSString *fixedName = [des.managedObjectClassName substringFromIndex:6];
                    des.managedObjectClassName = fixedName;
                }
                [fixedEntities addObject:des];
            }
            
            [_managedObjectModel setEntities:fixedEntities];
        }
        
        return _managedObjectModel;
    }
    
    -(NSManagedObjectModel*)managedObjectModel
    {
    if(_managedObjectModel){
    返回_managedObjectModel;
    }
    NSURL*modelURL=[[NSBundle mainBundle]URLForResource:@“myDataFile”,扩展名:@“momd”];
    _managedObjectModel=[[NSManagedObjectModel alloc]initWithContentsOfURL:modelURL];
    如果(@可用(macOS 10.14.6,*))
    {
    //什么也不做;不需要
    }
    其他的
    {
    NSArray*实体=[\u managedObjectModel实体];
    NSMutableArray*fixedEntities=[NSMutableArray阵列容量:entities.count];
    用于(N实体描述*实体中的des)
    {
    if([des.managedObjectClassName hasPrefix:@“MyApp.]”和&des.managedObjectClassName.length>6)
    {
    NSString*fixedName=[des.managedObjectClassName substringFromIndex:6];
    des.managedObjectClassName=固定名称;
    }
    [fixedEntities addObject:des];
    }
    [\u managedObjectModel setEntities:fixedEntities];
    }
    返回_managedObjectModel;
    }
    

    结果 以上完全解决了这个问题。在旧的macOS版本上,Core Data现在可以正确地为每个实体找到正确的NSManagedObject子类。它也适用于现代macOS版本。轻量级迁移也在所有版本上继续工作

    注意:此方法与NSManagedObject子类(由Xcode 12自动生成)中的
    @objc(LPProject)
    属性一起使用,并在Xcode中的核心数据模型编辑器GUI中将每个实体的“模块”设置为“当前产品模块”

    注2:我不知道这是否明智。它具有丑陋的黑客的所有特征,但是(A)它可以工作,(B)它对大多数用户使用的macOS 10.14.6+没有任何改动


    注3:如果使用此选项,请确保将
    6
    调整为模块名称中的字符数(包括句点)。否则,您将度过糟糕的一天。

    Update:在macOS 10.13上的已编译二进制文件上运行'otool-ov'命令表明定义了ObjC类和-printStuff方法。(这是有道理的,因为如果不是,崩溃也会发生在10.14和10.15上,编译器会抛出一个错误。)原因似乎是,出于某种原因,10.13上的核心数据没有返回正确的实体。注意:问题出现在macOS 10.14.5及以下版本上,因此我用正确的macOS版本更新了我的答案。
    warning: Unable to load class named 'MyApp.LPProject' for entity 'LPProject'.
    Class not found, using default NSManagedObject instead.
    
    - (NSManagedObjectModel *) managedObjectModel 
    {
        if (_managedObjectModel) {
            return _managedObjectModel;
        }
        
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"myDataFile" withExtension:@"momd"];
        _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        
        if (@available(macOS 10.14.6, *))
        {
            // Do nothing; not needed
        }
        else
        {
            NSArray<NSEntityDescription*> *entities = [_managedObjectModel entities];
            NSMutableArray *fixedEntities = [NSMutableArray arrayWithCapacity:entities.count];
    
            for (NSEntityDescription *des in entities)
            {
                if ([des.managedObjectClassName hasPrefix:@"MyApp."] && des.managedObjectClassName.length > 6) 
                {
                    NSString *fixedName = [des.managedObjectClassName substringFromIndex:6];
                    des.managedObjectClassName = fixedName;
                }
                [fixedEntities addObject:des];
            }
            
            [_managedObjectModel setEntities:fixedEntities];
        }
        
        return _managedObjectModel;
    }