CoreData学习-最好的一片文章

CoreData学习-最好的一片文章

分类: IOS重新上路2014-05-25 18:00 1937人阅读 评论(0) 收藏 举报

目录(?)[+]

写的很好的一篇教程,我什么时候能写出这么棒的文章来,还是继续努力学习吧。

iOS教程:Core Data数据持久性存储基础教程

其实最近更多的是在写这篇文章《iOS教程:使用持久性数据Core Data》,这篇是《iOS开发教程:Storyboard全解析-第一部分》这篇的后续,但是目前还没有完成,先放出一个持久性数据存储的教程以供参考。这其实是一篇翻译文章,英文的原文见这里。我翻译的过程中改变了一些内容以便适应我们中国人的口味,下面请看教程:

就像我一直说的,Core Data是iOS编程,乃至Mac编程中使用持久性数据存储的最佳方式,本质上来说,Core Data使用的就是SQLite,但是通过一系列特性避免了使用SQL的一些列的麻烦,不仅如此,他还能够合理管理内存,反正好处很多,我们推荐使用。

在这个教程中,我们将会创建一个Core Data的可视模型,之后再做一个Table View,让Table View的内容能够存储在数据模型里。

创建Core Data工程

首先打开Xcode,新建一个工程,选择Master-Detail模板。

我们这里使用FailedBankCD作为工程名称。

记住一定要选中Use StoryboardsUse Core Data, and Use Automatic Reference Counting 这几个选项,之后创建。

在开始之前,我想先把一些没有用的模板文件删除掉,选中一下四个文件。

  • FBCDMasterViewController.h
  • FBCDMasterViewController.m
  • FBCDDetailViewController.h
  • FBCDDetailViewController.m

删除之,一了百了,选择 “Move to Trash”。

现在使用Obj-c class的模板新建一个文件,命名为FBCDMasterViewController 他是个UITableViewController,记住下面的几个钩都不能选。

选中FBCDMasterViewController.h 在@end 之前的结尾行加入代码:

@property (nonatomic,strong) NSManagedObjectContext* managedObjectContext;

现在来到 .m 文件, 加入下面的语句。

@synthesize managedObjectContext;

如果你不知道什么是 “NSManagedObjectContext” 那也没关系,我们一会之后会谈这问题。

但是我们还是得先在Storyboard中删除掉我们刚才所删除的类所对应的视图,看图:

最后,选中FailedBanksCD.xcdatamodel,你会看到出现了一个可视编辑器我们接下来就用这个编辑器来编辑我们的数据模型,选中中间显示“Entity”(实体)的小泡泡,之后删除之。

如果你的编辑器看起来和下面的不一样,那么请将编辑器风格(Editor Style)改成visual view

OK,大功告成,如果现在启动这个App,你会发现他就是个空白的应用。

打开 FailedBanksCDAppDelegate.m,你会看到已经有一些预置的函数在这里了,这是为了建立Core Data的栈,包括如何创建数据模型,如何管理数据模型,如何建立持久性数据协调器等等。

如果这些术语看的你头疼,那也没关系,看了下面的解释你就会明白了:

  • Managed Object Model(管理数据模型): 你可以将这个东西看作是数据库的轮廓,或者结构。这里包含了各个实体的定义信息,一般来说,你会使用我们刚刚看过的视觉编辑器来操作这个物体,添加属性,建立属性之间的关系等等,当然你也可以使用代码。
  • Persistent Store Coordinator (持久性数据协调器): 你可以将这个东西看作是数据库连接库,在这里,你将设置数据存储的名字和位置,以及数据存储的时机。
  • Managed Object Context (管理数据内容):你可以将这一部分看作是数据的实际内容,这也是整个数据库中对我们而言最重要的部分(这还用说),基本上,插入数据,查询数据,删除数据的工作都在这里完成。

现在你还不用十分了解这些方法,因为我们暂时还用不到,但是了解一些概念总是好的。

创建数据模型

Core Data与SQLite不同的是,你不能够提取一个实体的某些属性,你只能够把整个实体提取出来,,之后再将他们分解。

让我们看看这是如何运作的,打开视觉编辑器(单击FailedBanksCD.xcodedatamode)

在底部的工具栏中,单机加号,新建一个实体。

新建实体之后,视觉编辑器会显示他的属性

将这个新实体命名为FailedBankInfo,之后单机这个实体,确保可视部分的第三个标签都是被选中的。在属性检查器的第三个标签里,你就会看到这个实体是NSManagedObject的子类,这是实体的默认类,我们现在先用着,将来我们会返回来修改为一个自定义的类。

现在,让我们加入一些属性吧(Atrributes),确保你的实体是被选中的状态,之后在中间的面板的底部按下加号,之后会出现一个像下面这样的选项框。

在Data Model属性检查器中,向下面那样将这个属性命名为“name”,type设置为“String”

 

现在,再继续增加两个新的属性“city”和“State”,类型都是字符串。

接下来,我们创建一个名为FailedBankDetails的实体,你一定已经会弄了吧?之后增加下面的属性在里面,zip(integer32属性)closeDate(date属性)updateDate(date属性)。

最后,我们将这两种实体连接起来,选择FailedBankInfo,按住中间面板的加号键不放,选择 “Add relationship”:

 

将这个relationship命名为“details”, 将目标设置为 “FailedBankDetails.”

好了,我们刚刚设置了一个连接两个实体的关系,这意味着,每一个FailedBankInfo的属性都将会拥有一个一个FailedBankDetails的实体,在设置的背后,Core Data会自动设置FailedBankInfo中实体的ID,不过这些我们不需要了解。

Apple官方建议说,每当你建立一个目标关系时,最好建立一个返回的关系,所以我们就按照官方的指示做吧。

在“FailedBankDetails” 中建立一个叫做 “info”的关系,设置他的目标是  “FailedBankInfo”,正好与“Details”这个关系是反着的。

接着,我们设置这两个关系的删除规则为“cascade”,这意味着,如果你删除了其中一个数据,另一个实体中的数据也会跟着本删除。

运行一下,怎么?崩溃了??

哦,原来是之前已经存在的一个数据已经无法被我们修改过的数据模型读取了,在这种情况下,只需要删除模拟器中的app,再重新运行就可以了。

测试我们的数据模型

不管你怎么想,测试可是我们编辑数据库中最重要的一步。

首先,我们向我们的数据库中加入一些测试数据,打开FailedBanksCDAppDelegate.m,在顶部application:didFinishLaunchingWithOptions方法中加入下面的代码:

NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *failedBankInfo = [NSEntityDescription
    insertNewObjectForEntityForName:@"FailedBankInfo"
    inManagedObjectContext:context];
[failedBankInfo setValue:@"Test Bank" forKey:@"name"];
[failedBankInfo setValue:@"Testville" forKey:@"city"];
[failedBankInfo setValue:@"Testland" forKey:@"state"];
NSManagedObject *failedBankDetails = [NSEntityDescription
    insertNewObjectForEntityForName:@"FailedBankDetails"
    inManagedObjectContext:context];
[failedBankDetails setValue:[NSDate date] forKey:@"closeDate"];
[failedBankDetails setValue:[NSDate date] forKey:@"updateDate"];
[failedBankDetails setValue:[NSNumber numberWithInt:12345] forKey:@"zip"];
[failedBankDetails setValue:failedBankInfo forKey:@"info"];
[failedBankInfo setValue:failedBankDetails forKey:@"details"];
NSError *error;
if (![context save:&error]) {
    NSLog(@"Whoops, couldn‘t save: %@", [error localizedDescription]);
}

在第一行,我们创建了一个指向我们的数据库的指针。

接着,我们为FailedBankInfo实体创建一个NSManagedObject实体,这里使用的是insertNewObjectForName的方法,每一个使用Core Data储存数据的方法都是由NSManagedObject中衍生出来的,当你创建了这个方法的实例的时候,你就可以给我们刚才在视觉编辑器中创建的模型中的任何属性进行赋值了。

之后我们设置一个测试数据,在这里数据只在内存中被修改,要是想要存入数据库,我们必须使用managedObjectContext方法

插入一个数据就是这么简单,完全不用SQL语句。

在运行之前,我们先用一些代码来列出我们数据库中的数据。

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription
    entityForName:@"FailedBankInfo" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (NSManagedObject *info in fetchedObjects) {
    NSLog(@"Name: %@", [info valueForKey:@"name"]);
    NSManagedObject *details = [info valueForKey:@"details"];
    NSLog(@"Zip: %@", [details valueForKey:@"zip"]);
}

这里我们创建一个叫做fetch request的新方法,你可以将一个fetch request看做Sql中的select语句,我们调用entityForName方法来获取一个指向FailedBankInfo的指针,之后使用setEntity方法来告诉我们的fetch request我们想要的是哪一种的实体。

之后,我们调用executeFetchRequest方法,将FailedBankInfo表中的所有数据推入一个数据缓存中,之后枚举所有NSManagedObject,使用valueForKey语句来调用其中的数据。

注意尽管我们从FailedBankInfo表中推出了所有的数据,我们仍然可以通过FailedBankInfo实体中的详细数据来访问FailedBankDetails这个数据体。

运行一下这个应用,目前你在屏幕上什么也看不到,你可以看看程序的输出窗口,你就可以看到输出结果了,每次你设置数据库的时候都应该做这样一个测试。

来看看SQL语句的真面目

我不知道你怎么想的,但是我个人喜欢看到每个语句后面的SQL语句,以确定这个程序正在按照我想的方式前进。

Apple提供了一个这样做的简便的方法,看下图,在Edit Scheme中选择Run,之后进入Arguments标签,加入下面的语句:“-com.apple.CoreData.SQLDebug 1”,完成之后,你会看到第二张图:

现在,每当你运行这个程序,Debug栏就会输出正在进行的活动的SQL语句了。

如果你对SQL语句不了解,也没有关系,没有人强制你学习这个烦人的东西,你可以一直使用Core Data。

自动生成的模型文件

目前为止,我们一直在用 NSManagedObject 来处理我们的实体,这并不是最好的方式,为什么呢?因为NSManagedObject不是一个 强型类(strongly typed class),所以,你只能够使用字符串来访问数据属性,如果打错了的话,就会造成错误,很不爽。

更好的方法是为每一个实体都创建一个模型文件,这样做好处很多,不赘述,Xcode提供了一个类生成器让我们方便地完成这个任务。

来试试看,打开 FailedBanksCD.xcdatamodel,点击 FailedBankInfo entity,进入File——NewFile。选择Core DataNSManagedObject 模板,之后创建:

 

你应该可以看到,你的工程中添加了一些新的文件,就是FailedBankInfo.h/m 和 FailedBankDetails.h/m,这些是一些非常简单的类,只是为了声明你在实体中添加的属性而已,Xcode会动态的添加语句进去,我们不用管这些。

为FailedBankDetails 实体做同样的事情。

但是这些自动生成的类中有一个问题我们必须手动解决,如果你打开FailedBankDetails.h来看,你就会发现info变量被声明称了FailedBankInfo,但是在FailedBankInfo.h中,他被声明称了NSManagedObject类,其实应该是FailedBankDetails类。

这是因为FailedBankInfo的生成器在FailedBankDetails的生成器之前运行,所以生成器不知道后面还有个这玩意。

你可以像上面那样手动修复,但是也有简单的方法,就是重新运行FailedBankInfo的生成器。

如果我们回到FailedBanksCD.xcdatamodel,当你查看实体的类的时候,你会发现他们已经被自动修改为自动创建的类。

为了测试,打开BCDAppDelegate.m ,在头部加入:

#import "FailedBankInfo.h"
#import "FailedBankDetails.h"

之后修改代码:

NSManagedObjectContext *context = [self managedObjectContext];
FailedBankInfo *failedBankInfo = [NSEntityDescription
    insertNewObjectForEntityForName:@"FailedBankInfo"
    inManagedObjectContext:context];
failedBankInfo.name = @"Test Bank";
failedBankInfo.city = @"Testville";
failedBankInfo.state = @"Testland";
FailedBankDetails *failedBankDetails = [NSEntityDescription
    insertNewObjectForEntityForName:@"FailedBankDetails"
    inManagedObjectContext:context];
failedBankDetails.closeDate = [NSDate date];
failedBankDetails.updateDate = [NSDate date];
failedBankDetails.zip = [NSNumber numberWithInt:12345];
failedBankDetails.info = failedBankInfo;
failedBankInfo.details = failedBankDetails;
NSError *error;
if (![context save:&error]) {
    NSLog(@"Whoops, couldn‘t save: %@", [error localizedDescription]);
}

// Test listing all FailedBankInfos from the store
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"FailedBankInfo"
    inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSArray *fetchedObjects = [context executeFetchRequest:fetchRequest error:&error];
for (FailedBankInfo *info in fetchedObjects) {
    NSLog(@"Name: %@", info.name);
    FailedBankDetails *details = info.details;
    NSLog(@"Zip: %@", details.zip);
}

这和我们上次测试的代码差不多,是不是?

创建一个表视图

打开 FBCDMasterViewController.h 声明一个数组,你懂得(如果不懂请见《如何创建一个简单的表》)

@property (nonatomic, strong) NSArray *failedBankInfos;

请注意,我们在测试的时候已经使用了一些方法来获取数据了,就在FBCDAppDelegate.m中的application:didFinishLaunchingWithOptions方法中,记得吗?

回到FailedBanksListViewController.m 作出以下修改:

// At very top, in import section
#import "FailedBankInfo.h"

// At top, under @implementation
@synthesize failedBankInfos;

修改 viewDidLoad 方法:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription
                                   entityForName:@"FailedBankInfo" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    NSError *error;
    self.failedBankInfos = [managedObjectContext executeFetchRequest:fetchRequest error:&error];
    self.title = @"Failed Banks";

}

这和我们测试的代码差不多是不是?我们使用一个 fetch request 来获取数据库中的数据,之后储存在内存中。

numberOfSectionsInTableView:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

numberOfRowsInSection:

- (NSInteger)tableView:(UITableView *)tableView
    numberOfRowsInSection:(NSInteger)section {
    return [failedBankInfos count];
}

cellForRowAtIndexPath :

- (UITableViewCell *)tableView:(UITableView *)tableView
    cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell =
        [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    // Set up the cell...
    FailedBankInfo *info = [failedBankInfos objectAtIndex:indexPath.row];
    cell.textLabel.text = info.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@, %@",
        info.city, info.state];

    return cell;
}

以上是制作一个表视图的代码,很熟悉吧,接下来我们在Storyboard中制作这个表视图,记得将cell的style设置为subtitle。

运行一下这个App,看看吧。

之后看些什么?

这是我制作完成的例子程序源码,欢迎下载。

这是原作者的样板程序: sample code for the project so far (direct download).

此条目是由 foreveryh 发表在 iPhone开发SDK 分类目录的。将固定链接加入收藏夹。

  • 上一篇
时间: 2024-11-06 17:48:01

CoreData学习-最好的一片文章的相关文章

学习Hadoop不错的系列文章

1)Hadoop学习总结 (1)HDFS简介 (2)HDFS读写过程解析 (3)Map-Reduce入门 (4)Map-Reduce的过程解析 (5)Hadoop的运行痕迹 (6)Apache Hadoop 版本 2)Hadoop-0.20.0源代码分析 (1)Hadoop-0.20.0源代码分析(01) 地址:http://blog.csdn.net/shirdrn/article/details/4569702 (2)Hadoop-0.20.0源代码分析(02) 地址:http://blog

《Yaf零基础学习总结》系列技术文章整理收藏

<Yaf零基础学习总结>系列技术文章整理收藏 Yaf零基础学习总结系列整理了Yaf的基础知识,对于Yaf入门的学习有很大的参考借鉴,收藏在这里,自己用到Yaf的时候随时查阅 1关于Yaf的一些说明[转Yaf作者]http://www.lai18.com/content/407120.html 2Yaf零基础学习总结1-Yaf框架简介http://www.lai18.com/content/407123.html 3Yaf零基础学习总结2-Yaf框架的安装http://www.lai18.com

《PHP扩展学习系列》系列技术文章整理收藏

<PHP扩展学习系列>系列技术文章整理收藏 1PHP扩展之文本处理(二)--PCRE正则表达式语法10--后向引用http://www.lai18.com/content/321526.html 2PHP扩展之文本处理(二)--PCRE正则表达式语法9--重复/量词http://www.lai18.com/content/321525.html 3PHP扩展之文本处理(二)--PCRE正则表达式语法11--断言http://www.lai18.com/content/321527.html 4

CoreData学习:Core Data Stack(Swift)

Core Data是苹果官方提供的一套框架,用来解决对象生命周期管理.对象关系图管理和持久化等方面相关的问题.Core Data是模型层的技术,Core Data帮助你构建代表程序状态的模型层.Core Data也是一种持久化技术,它可以将模型的状态持久化到磁盘.但它更重要的特点是:Core Data不只是一个加载和保存数据的框架,它也能处理内存中的数据. 什么是Core Data? 对于Core Data框架将经常困惑,以为是数据库.其实Core Data并不是数据库.如果它不是数据库,那么C

coreData学习简要

今天开始学习使用coreData. 2种方法: 1.在新建工程时,勾选使用 coreData,那么在工程里面已经有工程同名的coreData模型(model),而且在appDelegate里面有了三个属性,还有相关方法. @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; @property (readonly, strong, nonatomic) NSManagedObje

【NLP】蓦然回首:谈谈学习模型的评估系列文章(三)

基于NLP角度的模型评价方法 作者:白宁超 2016年7月19日19:04:51 摘要:写本文的初衷源于基于HMM模型序列标注的一个实验,实验完成之后,迫切想知道采用的序列标注模型的好坏,有哪些指标可以度量.于是,就产生了对这一专题进度学习总结,这样也便于其他人参考,节约大家的时间.本文依旧旨在简明扼要梳理出模型评估核心指标,重点达到实用.本文布局如下:第一章采用统计学习角度介绍什么是学习模型以及如何选择,因为现今的自然语言处理方面大都采用概率统计完成的,事实证明这也比规则的方法好.第二章采用基

学习SSD利器——最专业文章全集

扫描下面的二维码,或者微信搜索ssdfans关注公众号,每天都能看到一篇SSD精彩文章. SSD技术学习网 (http://www.ssdfans.com)是目前的中文网络上介绍SSD最专业的网站,文章都来自于业内技术人士.本文列出几篇适合SSD爱好者技术入门的文章,帮助SSD的选购.使用和技术开发. SSD介绍 何为SSD? Solid State Disk/Drive,固态硬盘也.现在,想必很多人都知道这东西,并且自觉或者不自觉的在使用着固态硬盘.一台刚买的新机子,如果配有固态硬盘,你看到系

学习Java 的第一篇文章

第一章   Java基础 1.学习方法: 01.找一本好书 初始阶段不适合,可以放到第二个阶段,看到知识点时,要进行验证 02.查看帮助文档和搜索引擎的使用 借助网络上的Blog文章 03.不要急功近利 不要抱着速成的想法,否则必然走弯路     学习编程不是一蹴而就的事情     付出的成本高,才能有一个高薪的收入 04.不要浮躁 不要什么都学,只学有用的 浮躁的程度和技术水平成反比的     走自己的路,让别人去浮躁去吧! 每天问问自己,我是不是开始浮躁了,不能人云亦云. 05.学习语言基础

AngularJs学习笔记--Guide教程系列文章索引

在很久很久以前,一位前辈向我推荐AngularJs.但当时我没有好好学习,仅仅是讲文档浏览了一次.后来觉醒了……于是下定决心好好理解这系列的文档,并意译出来(英文水平不足……不能说是翻译,有些实在是看不懂,希望大家在参观的过程中指出其中的错误).经过1个多月断断续续的努力,终于把Guide里面的文章基本上都弄出来.Guide中的部分章节,由于重复的部分似乎有点多,而且篇幅较短,这里就没有列出来. 文章列表如下: AngularJs学习笔记--bootstrap AngularJs学习笔记--ht