CoreData和MJExtension結(jié)合遇到的問題

最近在學(xué)習(xí)CoreData歇盼,在之前的學(xué)習(xí)Demo中進(jìn)行測(cè)試學(xué)習(xí),由于項(xiàng)目已經(jīng)存在评抚,現(xiàn)在需要引入CoreData框架豹缀。需做如下修改:
1.需將已存在的model繼承自NSManagedObject;
2.創(chuàng)建.xcdatamodeld映射文件慨代;
3.添加需要使用CoreData的model實(shí)體(Entity)邢笙;將Entity->Show the Data Model inspector->Codegen修改為Manual/None(即不自動(dòng)生成實(shí)體類,因?yàn)閙odel實(shí)體類已經(jīng)存在了侍匙,如果修改的話會(huì)再次生成同名實(shí)體類氮惯,導(dǎo)致類文件重復(fù)錯(cuò)誤)。


65C27B5A-512E-42F8-A73D-BF9FB1872EE1.png

實(shí)體類中NSArray想暗、NSDictionary妇汗、NSData類型對(duì)應(yīng)CoreData的Transformable類型。在與MJExtension結(jié)合使用時(shí)不能對(duì)屬性為NSArray(保存自定義model)的字段采用映射文件關(guān)聯(lián)關(guān)系方式江滨。如果使用關(guān)聯(lián)關(guān)系NSArray類型數(shù)

采用關(guān)聯(lián)關(guān)系One To Many 時(shí)屬性類型必須是NSSet而非NSArray铛纬;Transformable則可以使用NSArray;但當(dāng)與MJExtension結(jié)合使用時(shí)唬滑,Transformable類型屬性不能使用NSSet告唆,會(huì)導(dǎo)致數(shù)據(jù)丟失。
總結(jié)(集合數(shù)據(jù)情況):
1.采用關(guān)聯(lián)關(guān)系:使用NSSet類型定義屬性晶密,NSArray會(huì)崩潰擒悬;
2.Transformable類型:
a)普通情況:使用NSArray/NSSet定義屬性跳昼;
b)與MJExtension結(jié)合使用:NSArray定義屬性愕乎,NSSet會(huì)數(shù)據(jù)丟失待锈。

CoreData本地雖然對(duì)數(shù)據(jù)進(jìn)行了緩存膜赃,但查詢返回?cái)?shù)據(jù)為空艺骂。此時(shí)應(yīng)采用Transformable類型抹腿。

#import "ZTCDBaseModel.h"
#import "UserInfo.h"


@interface User : ZTCDBaseModel

@property(nonatomic,copy) NSString*                     userName;
@property(nonatomic,copy) NSString*                     password;
@property(nonatomic,copy) NSArray<User*>*         childs;
@property(nonatomic,strong) UserInfo*                   info;
@end
3E2FE308-4A79-4D42-AE5B-CC9939191407.png

在使用Transformable類型時(shí)深浮,實(shí)際上是將NSArray剩辟、NSDictionary對(duì)象轉(zhuǎn)換成NSData進(jìn)行存儲(chǔ),此時(shí)需要我們執(zhí)行轉(zhuǎn)換器躯保,如果不指定在讀取包含NSArray旋膳、NSDictionary類型屬性(屬性中保存自定義model)的model會(huì)報(bào)錯(cuò)

-[XXX initWithCoder:]: unrecognized selector sent to instance 0x60000091a180

系統(tǒng)為我們提供了NSValueTransformer轉(zhuǎn)換器,在關(guān)系映射文件選中Transformable類型屬性途事,在Show the Data Model inspector中的Value Transformer寫入NSValueTransformer來(lái)指定轉(zhuǎn)換器可以正常進(jìn)行數(shù)據(jù)存取操作验懊。


D981DE14-5D2F-440E-812D-4F6F58851AFC.png

但是NSValueTransformer是轉(zhuǎn)換成NSData進(jìn)行存取的,讀取出的OC對(duì)象為NSData類型尸变,需要再存進(jìn)行轉(zhuǎn)換义图,NSData->NSArray/NSDictionary。

每次讀取然后轉(zhuǎn)換比較麻煩召烂,方便起見碱工,我們可以自定義轉(zhuǎn)換器,在轉(zhuǎn)換器中統(tǒng)一處理奏夫。繼承自NSValueTransformer類痛垛,重寫一下方法:

- (nullable id)transformedValue:(nullable id)value;           // by default returns value
- (nullable id)reverseTransformedValue:(nullable id)value; 

例如:

#import "ZTCoreDataTransformer.h"

@implementation ZTCoreDataTransformer

/**
 轉(zhuǎn)化方法實(shí)現(xiàn)(如:將OC對(duì)象轉(zhuǎn)換成Sqlite可存儲(chǔ)的對(duì)象-序列化過(guò)程)

 @param value 待轉(zhuǎn)換數(shù)據(jù)
 @return 轉(zhuǎn)換結(jié)果
 */
- (id)transformedValue:(id)value{
    if (value == nil) {
        return nil;
    }
    if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]){
        return [NSKeyedArchiver archivedDataWithRootObject:value];
    }
    return nil;
}

/**
 逆向轉(zhuǎn)換實(shí)現(xiàn)(如:將Sqlite存儲(chǔ)的對(duì)象轉(zhuǎn)換成OC對(duì)象-反序列化過(guò)程)

 @param value 待轉(zhuǎn)換數(shù)據(jù)
 @return 轉(zhuǎn)換結(jié)果
 */
- (id)reverseTransformedValue:(id)value{
    if (value) {
       return [NSKeyedUnarchiver unarchiveObjectWithData:value];
    }
    return nil;
}
@end

然后將轉(zhuǎn)換器指定為自定義的。

采用歸檔(NSKeyedArchiver)方式進(jìn)行本地化存儲(chǔ)的類還需要實(shí)現(xiàn)NSCoding協(xié)議桶蛔。
1.一般model直接實(shí)現(xiàn)NSCoding協(xié)議即可;
使用MJExtension直接在model的實(shí)現(xiàn)中使用MJCodingImplementation宏即可;

2.當(dāng)需要?dú)w檔的model對(duì)象繼承自NSManagedObject時(shí)漫谷,無(wú)法通過(guò)init進(jìn)行初始化仔雷。

- (void)encodeWithCoder:(NSCoder *)aCoder{
    [aCoder encodeObject:self.userName forKey:@"userName"];
    [aCoder encodeObject:self.password forKey:@"password"];
    [aCoder encodeObject:self.childs forKey:@"childs"];
    [aCoder encodeObject:self.info forKey:@"info"];
}

- (id)initWithCoder:(NSCoder *)aDecoder{
    NSEntityDescription* descr = [NSEntityDescription entityForName:NSStringFromClass(self.class) inManagedObjectContext:self.class.shareManage];
    self = [[self.class alloc] initWithEntity:descr insertIntoManagedObjectContext:nil];
    if (self){
        self.userName = [aDecoder decodeObjectForKey:@"userName"];
        self.password = [aDecoder decodeObjectForKey:@"password"];
        self.childs = [aDecoder decodeObjectForKey:@"childs"];
        self.info = [aDecoder decodeObjectForKey:@"info"];
    }
    return self;
}

使用MJExtension時(shí)需自定義宏:

#define ZTCoreDataCodingImplementation \
- (id)initWithCoder:(NSCoder *)decoder \
{ \
NSEntityDescription* descr = [NSEntityDescription entityForName:NSStringFromClass(self.class) inManagedObjectContext:self.class.shareManage];\
self = [[self.class alloc] initWithEntity:descr insertIntoManagedObjectContext:nil];\
if (self) { \
[self mj_decode:decoder]; \
} \
return self; \
} \
\
- (void)encodeWithCoder:(NSCoder *)encoder \
{ \
[self mj_encode:encoder]; \
}

在model實(shí)現(xiàn)(.m)文件中使用ZTCoreDataCodingImplementation宏即可。shareManage是CoreData的上下文舔示。我自定義了一個(gè)BaseMode碟婆。

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import <MJExtension/MJExtension.h>

/**
 需要CoreData本地化的模型集成此類;需創(chuàng)建與boundle id最后名稱一致的.xcdatamodeld映射文件
 */
@interface ZTCDBaseModel : NSManagedObject

+ (NSManagedObjectContext*)shareManage;

+ (id)ZT_JSONToModel:(id)JSON;

+ (id)ZT_fetchModel:(NSDictionary*)fetchParams;
@end
#import "ZTCDBaseModel.h"

@interface ZTCDBaseModel()

@end

@implementation ZTCDBaseModel

+ (NSManagedObjectContext*)shareManage{
    static NSManagedObjectContext* context;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
        NSString* modelName = [[[NSBundle mainBundle] bundleIdentifier] componentsSeparatedByString:@"."].lastObject;
        NSURL* url = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:modelName ofType:@"momd"]];
        if (!url) {
            NSString* errorMsg = [NSString stringWithFormat:@"%@.xcdatamodeld文件不存在!L璧尽竖共!",modelName];
            NSAssert(url,errorMsg);
        }
        NSManagedObjectModel* model = [[NSManagedObjectModel alloc] initWithContentsOfURL:url];
        NSPersistentStoreCoordinator* storeCoordicate = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
        NSString* dataPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).lastObject stringByAppendingFormat:@"/%@.sqlite",modelName];
        [storeCoordicate addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[NSURL fileURLWithPath:dataPath] options:nil error:nil];
        context.persistentStoreCoordinator = storeCoordicate;
        context.undoManager = nil;
    });
    return context;
}

+ (id)ZT_JSONToModel:(id)JSON{
    if (!JSON) {
        return nil;
    }
    id result = [JSON isKindOfClass:[NSArray class]] ? [self.class mj_objectArrayWithKeyValuesArray:JSON context:self.shareManage] : [self.class mj_objectWithKeyValues:JSON context:self.shareManage];
    NSError* error;
    [self.shareManage save:&error];
    return error ? nil : result;
}
@end

個(gè)人筆記,還沒整理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俺祠,一起剝皮案震驚了整個(gè)濱河市公给,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜘渣,老刑警劉巖淌铐,帶你破解...
    沈念sama閱讀 212,383評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蔫缸,居然都是意外死亡腿准,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拾碌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吐葱,“玉大人街望,你說(shuō)我怎么就攤上這事〉芘埽” “怎么了灾前?”我有些...
    開封第一講書人閱讀 157,852評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)窖认。 經(jīng)常有香客問我豫柬,道長(zhǎng),這世上最難降的妖魔是什么扑浸? 我笑而不...
    開封第一講書人閱讀 56,621評(píng)論 1 284
  • 正文 為了忘掉前任烧给,我火速辦了婚禮,結(jié)果婚禮上喝噪,老公的妹妹穿的比我還像新娘础嫡。我一直安慰自己,他們只是感情好酝惧,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,741評(píng)論 6 386
  • 文/花漫 我一把揭開白布榴鼎。 她就那樣靜靜地躺著,像睡著了一般晚唇。 火紅的嫁衣襯著肌膚如雪巫财。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評(píng)論 1 290
  • 那天哩陕,我揣著相機(jī)與錄音平项,去河邊找鬼。 笑死悍及,一個(gè)胖子當(dāng)著我的面吹牛闽瓢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播心赶,決...
    沈念sama閱讀 39,076評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼扣讼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了缨叫?” 一聲冷哼從身側(cè)響起椭符,我...
    開封第一講書人閱讀 37,803評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎弯汰,沒想到半個(gè)月后艰山,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡咏闪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,582評(píng)論 2 327
  • 正文 我和宋清朗相戀三年曙搬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,716評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡纵装,死狀恐怖征讲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情橡娄,我是刑警寧澤诗箍,帶...
    沈念sama閱讀 34,395評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站挽唉,受9級(jí)特大地震影響滤祖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓶籽,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,039評(píng)論 3 316
  • 文/蒙蒙 一匠童、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塑顺,春花似錦汤求、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至裤唠,卻和暖如春挤牛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背种蘸。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工赊颠, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人劈彪。 一個(gè)月前我還...
    沈念sama閱讀 46,488評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像顶猜,于是被迫代替她去往敵國(guó)和親沧奴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,612評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容