欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS在framework中使用CoreData出现崩溃问题及解决方法

程序员文章站 2022-07-28 14:48:55
公司项目中有一个功能,保存授权令牌数据。最开始只有一条数据,所以就直接保存在了userdefaults中。后来需要两条数据,还是保存在userdefaults中,其中一条为固定的,另一条不固定可以进行替换或删除。最近又需要保存多条数据,那么usedefaults就不适合了,就考虑使用数据库。iOS中 ......

公司项目中有一个功能,保存授权令牌数据。最开始只有一条数据,所以就直接保存在了userdefaults中。后来需要两条数据,还是保存在userdefaults中,其中一条为固定的,另一条不固定可以进行替换或删除。最近又需要保存多条数据,那么usedefaults就不适合了,就考虑使用数据库。ios中可以选择fmdb或coredata,两者都是基于sqlite数据库的封装,其中coredata是苹果开发的orm类型的数据库,在数据量比较少时,两者性能差别不是很大。因为需要在framework中使用,所以尽量不要多引用第三方库,防止和原项目中的库冲突。并且之前项目中用到过在framework中使用coredata,比较熟悉,所以决定这次也用coredata。

在framework工程中,新建data model,添加entity和attributes,生成对应的nsmanagedobject子类,在coredataproperties扩展中添加一些自定义方法,然后打包framework,并将xcdatamodel文件打包到bundle文件中(为mom格式),最后把.framework和.bundle文件拖入原工程中。

编译运行,崩溃并提示

coredata: warning: unable to load class named 'atoken' for entity 'atoken'. class not found, using default nsmanagedobject instead.

搜索之后发现这个回答

不过这是使用swift时遇到的问题,但是我用的oc,问题没有解决。

又经过一段时间的搜索,发现有一个问题和我遇到的非常相似

按照上面的方法在build setting-other linker flags中加入-objc,运行,如果可以的话就不用继续往下看了。

但是我的程序运行之后还是崩溃,但是没有崩溃提示,所以我就把-objc去掉了。

过了两天,经过各种搜索尝试后,还是没有解决。今天来的时候,我想是不是原有工程中的一些项有影响。然后就新建一个测试项目,把之前生成的framework放进来,但还是提示上面那个错误。我想既然提示没有找到这个类,就在崩溃的地方手动调用initialize方法来加载这个类,这样改过后,错误提示变成这样的

unrecongized selector send to instance

找不到对应的方法,很奇怪怎么会没有呢,百度怎么输出类中的所有方法,结果是这样的

#import <objc/runtime.h>
#import <objc/message.h>

-(void)getallmethods {
    unsigned int count;
    method *methods = class_copymethodlist([atoken class],   &count);
    for (int i = 0; i < count; i++) {
        method method = methods[i];
        sel selector = method_getname(method);
        nsstring *name =   nsstringfromselector(selector);
        nslog(@"方法名字 ==== %@",name);
    }
}

在测试项目中调用这个方法,没有输出一个方法,这些方法明明就有,在自动生成的coredataproperties扩展中,难道是扩展的问题。我就在网上搜索了这个问题,发现了这个答案

按照上面的方法在build setting-other linker flags中加入-objc,再次运行,发现可以输出类中所有的方法了,但还是崩溃在向coredata中插入数据的时候,不过好在这次有错误提示

2019-01-25 13:26:02.833971+0800 frameworktest[61131:21155913] *** terminating app due to uncaught exception 'nsinternalinconsistencyexception', reason: 'class 'atoken' for entity 'atoken' has an illegal override of nsmanagedobject -isequal:'

原来是重写isequal方法导致的,想起之前为了比较自定义类的对象是否相等重写了这个方法,是这样写的

- (bool)isequal:(id)object {
    if (self == object) {
        return yes;
    }
    if (![object iskindofclass:[self class]]) {
        return no;
    }
    return [self isequaltotoken:object];
}

- (bool)isequaltotoken:(atoken *)token {
    if (!token) {
        return no;
    }
    bool haveequaltoken = (!self.token && !token.token) || [self.token isequaltodata:token.token];
    bool haveequaldefault = self.isdefault == token.isdefault;
    bool haveequalsavetime = (!self.savetime && !token.savetime) || [self.savetime isequaltodate:token.savetime];
    bool haveequalreadcount = self.readcount == token.readcount;
    return haveequaltoken && haveequaldefault && haveequalsavetime && haveequalreadcount;
}

- (nsuinteger)hash {
    nsuinteger hash = [super hash];
    hash = [self.token hash] ^ self.isdefault ^ self.readcount;
    return hash;
}

所以就把isequal和hash方法注释掉,再重新生成framework,并放到测试项目中,运行,终于没有崩溃了。

困扰了好几天的问题就这样解决了,记录下来,希望可以帮助遇到同样问题的人。