最近在學(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ò)誤)。
實(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
在使用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ù)存取操作验懊。
但是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è)人筆記,還沒整理