ios10.3之CoreData的详细教程

首先如果要使用CoreData可以选择在初创项目时选择添加coredata,也可以选择自己添加coredata文件

系统添加coredata后会在Appdelegate类中自动添加一个persistentContainer属性,和一个saveContext方法。在.m中还为persistentContainer写了getter

- (NSPersistentContainer *)persistentContainer {
    // The persistent container for the application. This implementation creates and returns a container, having loaded the store for the application to it.
    @synchronized (self) {
        if (_persistentContainer == nil) {
            _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"XWMyCoreDataDemo"];
            [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
                if (error != nil) {
                    NSLog(@"Unresolved error %@, %@", error, error.userInfo);
                    abort();
                }
            }];
        }
    }
    
    return _persistentContainer;
}
- (void)saveContext {
    NSManagedObjectContext *context = self.persistentContainer.viewContext;
    NSError *error = nil;
    if ([context hasChanges] && ![context save:&error]) {
        // Replace this implementation with code to handle the error appropriately.
        // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
        NSLog(@"Unresolved error %@, %@", error, error.userInfo);
        abort();
    }
}
需要特别注意的是两个方法实现中都有abort()函数,这个函数会造成程序崩溃,如果是开发模式,可以利于调试,如果是已上架模式最好移除这个函数,以免影响用户体验。

然后可以找到.xcdatamodeld文件,开始添加模型,在我的demo中添加了Person和Card两个模型,详情如下

Person中添加了两个属性name和age,类型分别为String和int32_t,card中也添加了两个属性color和size,类型均为NSObject(截图时我想尝试下Decimal数据类型尝试了下,后来改成Transformable,即NSObject类型)

需要注意的是一般我们都会选择手动生成继承自NSManagedObject的Person和Card的类方便我们查看等,而.xcdatamodeld文件在编译时会自动生成同样的Person和Card类,所以我们可以选择禁用模型的自动生成功能,如下图所示,我们可以选择模型,然后找到Class中Codegen将其改成Manul/None,即可禁止其自动生成模型子类。

然后我们还可以在文件中设置两个模型的关系,如下图所示,我们可以点击relationship中的+,添加关系,

需要注意的是添加单相关系的时候inverse是不会有值的,只有双向关系,或者有其他模型引用这个模型时才会有值。

其中relationship中的值即为生成类时系统会自动生成的属性,可以看到选择属性时右方可以选择ToOne或者ToMany,即一个Person模型可以对应几个Card,如果选择一对多

那么系统会自动生成一个集合属性,并且会生成相关的添加值的方法。然后我们可以按照下图选择生成Person和Card的类文件。

生成后项目文件如下所示

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

@class Card;

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSManagedObject

@end

NS_ASSUME_NONNULL_END

#import "Person+CoreDataProperties.h"
 
#import "Person+CoreDataClass.h"
#import "Card+CoreDataClass.h"

@implementation Person

@end
 
#import "Person+CoreDataClass.h"


NS_ASSUME_NONNULL_BEGIN

@interface Person (CoreDataProperties)

+ (NSFetchRequest<Person *> *)fetchRequest;

@property (nullable, nonatomic, copy) NSString *name;
@property (nonatomic) int32_t age;
@property (nullable, nonatomic, retain) NSSet<Card *> *cards;

@end
 

@interface Person (CoreDataGeneratedAccessors)
//用于添加属性值的方法
- (void)addCardsObject:(Card *)value;
- (void)removeCardsObject:(Card *)value;
- (void)addCards:(NSSet<Card *> *)values;
- (void)removeCards:(NSSet<Card *> *)values;

@end

NS_ASSUME_NONNULL_END
#import "Person+CoreDataProperties.h"
@implementation Person (CoreDataProperties)

+ (NSFetchRequest<Person *> *)fetchRequest {
	return [[NSFetchRequest alloc] initWithEntityName:@"Person"];
}

@dynamic name;
@dynamic age;
@dynamic cards;

@end
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@class NSObject, Person;

NS_ASSUME_NONNULL_BEGIN

@interface Card : NSManagedObject

@end

NS_ASSUME_NONNULL_END

#import "Card+CoreDataProperties.h"
#import "Card+CoreDataClass.h"
#import "Person+CoreDataClass.h"

@implementation Card

@end 
#import "Card+CoreDataClass.h"


NS_ASSUME_NONNULL_BEGIN

@interface Card (CoreDataProperties)

+ (NSFetchRequest<Card *> *)fetchRequest;

@property (nullable, nonatomic, retain) NSObject *color;
@property (nullable, nonatomic, copy) NSObject *size;
@property (nullable, nonatomic, retain) Person *owner;

@end 
NS_ASSUME_NONNULL_END
#import "Card+CoreDataProperties.h"

@implementation Card (CoreDataProperties)

+ (NSFetchRequest<Card *> *)fetchRequest {
	return [[NSFetchRequest alloc] initWithEntityName:@"Card"];
}

@dynamic color;
@dynamic size;
@dynamic owner;

@end
可以发现模型生成的类都是继承自NSManagedObject,且相关属性都使用了@dynamic,也就是系统不会自动生成getter和setter,且在使用的过程中可以发现如果 使用alloc初始化模型的时候是会报错的!

最后附上使用过程

#import "ViewController.h"
#import "Card+CoreDataClass.h"
#import "Person+CoreDataClass.h"
#import "AppDelegate.h"
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSManagedObjectContext *context = delegate.persistentContainer.viewContext; //context常用
    //创建一个Person模型对象 模型对象初始化必须有一个NSEntityDescription
    Person *p = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:context];
    p.name = @"Will";
    p.age = 24;
    //创建一个Card模型对象 
    Card *card = [NSEntityDescription insertNewObjectForEntityForName:@"Card" inManagedObjectContext:context];
    card.color = [UIColor redColor];
    card.size = NSStringFromCGSize(CGSizeMake(70, 100));
    [p addCardsObject:card];
    NSError *error = nil;
    [context save:&error];	//保存操作
    if (error) {
        NSLog(@"%@",error.userInfo);
    }
    /**    下面是查询操作,可以删除上面代码,重新运行       */
//    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Person"];	//初始化一个Person的查询请求
    NSFetchRequest *request = [Person fetchRequest];	//系统自动生成了获取查询请求的方法
    NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES];//为请求设置排序实例
    request.sortDescriptors = @[descriptor];
    
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name like '?il?'"];//为请求设置过滤条件
    request.predicate = predicate;
    NSArray *array = [context executeFetchRequest:request error:&error]; //根据请求执行查找,结果存于一个数组。
    for (Person *p in array) {
        NSLog(@"%@,%d,%@",p.name,p.age,p.cards);
    }
    
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


@end
如果对sqlite熟悉的话,可以发现查找的工作很熟悉,就相当于数据库执行"select * from Person order by name where name like '?il?'"的操作,以前系统为我们提供的context查找操作是同步的(现在默认的查找操作默认的是异步的),所以当时如果查询操作是很耗时的话,会影响性能,当时的解决办法是进行异步查询操作
NSAsynchronousFetchRequest *request = [[NSAsynchronousFetchRequest alloc]initWithFetchRequest:[Person fetchRequest] completionBlock:^(NSAsynchronousFetchResult * _Nonnull result) {
        if (result) {
            NSLog(@"%@",result.finalResult);
            NSLog(@"%@",[NSThread currentThread]);
            NSLog(@"%@",@(context.concurrencyType));
        }
    }];
    [context executeRequest:request error:&error];
但是不管是同步还是异步的查询操作都是在主线程进行的,如果想要放在子线程的话需要更改context的concurrencyType,因为concurrencyType是readonly,且没有找到相关设置方法,所以目前我采用的重新构建一个context。
NSManagedObjectContext *backContext = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [backContext setPersistentStoreCoordinator:context.persistentStoreCoordinator];
    
    NSAsynchronousFetchRequest *request = [[NSAsynchronousFetchRequest alloc]initWithFetchRequest:[Person fetchRequest] completionBlock:^(NSAsynchronousFetchResult * _Nonnull result) {
        if (result) {
            NSLog(@"%@",result.finalResult);
            NSLog(@"%@",[NSThread currentThread]);
            NSLog(@"%@",@(context.concurrencyType));
        }
    }];
    [backContext executeRequest:request error:&error];
如果想要删除存储的模型的话
NSFetchRequest *request = [Person fetchRequest];
    NSArray *array = [context executeFetchRequest:request error:&error];
    for (Person *p in array) {
        if ([p.name isEqualToString:@"will"]) {
            [context deleteObject:p];
            [context save:&error];
        }
    }
很重要的一点是, 每次进行操作后需要保存才能生效!


  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值