打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
corea data学习—2

这是系列教程的第二部分,有助于你加快掌握基本的Core Data内容。

系列教程一中,我们为对象建立了可视化数据模型,运行了快速肮脏测试并勾在一个表视图(table view)中来显示。而在这个教程,我们将讨论如何把已有的数据导入或者预先载入到Core Data里面,这样我们的应用开始时会有一些好的默认数据。

在系列教程的最后部分,我们将讨论如何使用NSFetchedResultsController来优化应用,降低内存开销和提升响应时间。

Preloading / Importing Existing Data

预载/导入已有数据

我们要如何在Core Data中预先载入数据呢?流行的解决方案有两种:

  • 启动时从外部源填入Core Data对此,注意到数据库还没有导入,应用可以启动时从外部来源(例如SQLite数据库或是XML文件)读取数据。
  • SQLite数据库中预先填充对此我们可以Core Data在模型基础上建立数据库结构,然后使用工具来填入数据库。这类工具可以是基于Core Data API的Mac或者iPhone应用,或是一些直接填入SQLite数据库的程序。一旦数据库填好了,只需将其包含到应用里面作为默认数据库,在不存在已有的数据库情况下。

我们将会采用第二种方式,因为它更简单更有效。为了填充数据库,我们只需稍微扩展一下已有的Python脚本。

注意到为什么用Python脚本而不是用基于Core Data API的工具来来导入数据,是因为我们现在有点走底层的样子,将来可能会容易损坏…但是对于本教程我认为第一,由于我们刚刚接触了SQLite,这样对学习的经验巩固更好,而且对事情的进展看的更加清楚;第二,更简单!

所以,让我们拿出工程中产生的sqlite数据库的拷贝。找出相关文件的最简单的方法就是在程序委托(application delegate)中persistentStoreCoordinator函数里面storeUrl一行下方设置一个断点。你可以通过检测storeUrl变量的内容来获取sqlite数据库备份文件的完整路径。找到它并拷到你的Python脚本目录。

一旦你找到数据库,使用sqlite3来简单看看数据库的模样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
sqlite3 FailedBanksCD.sqlite
 
sqlite3> .schema
CREATE TABLE ZFAILEDBANKDETAILS ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER,
    Z_OPT INTEGER, ZZIP INTEGER, ZINFO INTEGER, ZUPDATEDDATE TIMESTAMP,
    ZCLOSEDATE TIMESTAMP );
CREATE TABLE ZFAILEDBANKINFO ( Z_PK INTEGER PRIMARY KEY, Z_ENT INTEGER,
    Z_OPT INTEGER, ZDETAILS INTEGER, ZNAME VARCHAR, ZSTATE VARCHAR,
    ZCITY VARCHAR );
CREATE TABLE Z_METADATA (Z_VERSION INTEGER PRIMARY KEY,
    Z_UUID VARCHAR(255), Z_PLIST BLOB);
CREATE TABLE Z_PRIMARYKEY (Z_ENT INTEGER PRIMARY KEY, Z_NAME VARCHAR,
    Z_SUPER INTEGER, Z_MAX INTEGER);
CREATE INDEX ZFAILEDBANKDETAILS_ZINFO_INDEX ON ZFAILEDBANKDETAILS (ZINFO);
CREATE INDEX ZFAILEDBANKINFO_ZDETAILS_INDEX ON ZFAILEDBANKINFO (ZDETAILS);
 
sqlite> select * from ZFAILEDBANKINFO;
1|2|1|1|Test Bank|Testland|Testville
2|2|1|2|Test Bank|Testland|Testville
3|2|1|3|Test Bank|Testland|Testville
 
sqlite> select * from ZFAILEDBANKDETAILS;
1|1|1|12345|1|292794835.855615|292794835.679693
2|1|1|12345|2|292794875.943392|292794875.768675
3|1|1|12345|3|292795809.375025|292795809.215297
 
sqlite> select * from Z_PRIMARYKEY;
1|FailedBankDetails|0|3
2|FailedBankInfo|0|3

这里有段快速描述。Z_METADATA包含了一些关于Core Data需要实现的模型信息。Z_PRIMARYKEY包含了(在其他东西里面)各个实体所用到的最大key。

至于ZFAILEDBANKINFO跟ZFAILEDBANKDETAILS,这些是我们的主要数据表。Z_PK是各个表的唯一id,Z_ENT是他们的实体id(跟Z_PRIMARYKEY表中列出的一样),最后那些是我们的普通字段。

现在让我们写一段Python脚本来填充这个数据库,通过读取老数据库的内容,在新数据库建立相应的行。脚本如下:

import sqlite3;            from datetime import datetime, date;            import time            inConn = sqlite3.connect('banklist.sqlite3')            outConn = sqlite3.connect('FailedBanksCD.sqlite')            inCursor = inConn.cursor()            outCursor = outConn.cursor()            outConn.execute("DELETE FROM ZFAILEDBANKINFO")            outConn.execute("DELETE FROM ZFAILEDBANKDETAILS")            maxId = 0            inCursor.execute("select * from failed_banks")            for row in inCursor:            closeDate = datetime.strptime(row[5], "%Y-%m-%d %H:%M:%S")            updatedDate = datetime.strptime(row[6], "%Y-%m-%d %H:%M:%S")            closeDateSecs = time.mktime(closeDate.timetuple())            updatedDateSecs = time.mktime(updatedDate.timetuple())            # Convert time references secs to NSDate reference            deltaSecs = time.mktime((2001, 1, 1, 0, 0, 0, 0, 0, 0))            closeDateSecs = closeDateSecs - deltaSecs            updatedDateSecs = updatedDateSecs - deltaSecs            if row[0] > maxId:            maxId = row[0]            # Create ZFAILEDBANKINFO entry            vals = []            vals.append(row[0]) # Z_PK            vals.append(2) # Z_ENT            vals.append(1) # Z_OPT            vals.append(row[0]) # ZDETAILS            vals.append(row[1]) # ZNAME            vals.append(row[3]) # ZSTATE            vals.append(row[2]) # ZCITY            outConn.execute("insert into ZFAILEDBANKINFO values(?, ?, ?, ?, ?, ?, ?)", vals)            # Create ZFAILEDBANKDETAILS entry            vals = []            vals.append(row[0]) # Z_PK            vals.append(1) # Z_ENT            vals.append(1) # Z_OPT            vals.append(row[4]) # ZZIP            vals.append(row[0]) # ZINFO            vals.append(closeDateSecs) # ZUPDATEDATE            vals.append(updatedDateSecs) # ZCLOSEDATE            outConn.execute("insert into ZFAILEDBANKDETAILS values(?, ?, ?, ?, ?, ?, ?)", vals)            outConn.execute("update Z_PRIMARYKEY set Z_MAX=?", [maxId])            outConn.commit()

这应该很容易懂,唯一技巧的地方在于转换旧数据库所存文件(字符串)的格式到新的数据库中 (Jeff R.指出NSdate跟Python使用的date格式不同,所以也要转换)

测试一下Python脚本,如果一切顺利,你会看到填充好的数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
python coreData.py
 
sqlite3 FailedBanksCD.sqlite
 
sqlite> select * from ZFAILEDBANKINFO limit 3;
1|2|1|1|Desert Hills Bank|AZ|Phoenix
2|2|1|2|Unity National Bank|GA|Cartersville
3|2|1|3|Key West Bank|FL|Key West
 
sqlite> select * from ZFAILEDBANKDETAILS limit 3;
1|1|1|57060|1|1269576000|1269576000
2|1|1|34678|2|1269576000|1269576000
3|1|1|34684|3|1269576000|1269576000

一旦你的数据库填入了正确的数据,将数据库文件拖到你的XCode工程Resource文件夹里面。然后打开FailedBanksCDAppDelegate.m,找到persistentStoreCoordinator函数,用下面一行替换掉storeUrl:

NSString *storePath = [[self applicationDocumentsDirectory]            stringByAppendingPathComponent: @"FailedBanksCD.sqlite"];            NSURL *storeUrl = [NSURL fileURLWithPath:storePath];            // Put down default db if it doesn't already exist            NSFileManager *fileManager = [NSFileManager defaultManager];            if (![fileManager fileExistsAtPath:storePath]) {            NSString *defaultStorePath = [[NSBundle mainBundle]            pathForResource:@"FailedBanksCD" ofType:@"sqlite"];            if (defaultStorePath) {            [fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];            }            }

以上所有工作都是为了确认sqlite文件已经在文档目录里面,并且如果没有(例如应用第一次运行)就会从bundle拷贝包含的数据库。然后Core Data会开始使用预载数据,这样我们就准备好了!从iPhone模拟器目录删除老的SQLITE3文件(或是单击iPhone Simulator\Reset Contents and Settings来清除一切),然后重启应用。如果一切顺利,你应该能看到预先填入的银行列表!

下一步要做什么?

此时此刻,我们有了一个跟之前SQLite例子一样有效的明细视图。然而,有了Core Data,只需要再加几个步骤,效率还能提升。因此下个教程我们来讨论如何用NSFetchedResultsController来提升效率!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
第七章:Python之数据库编程
浅谈Python自带数据库SQLite3模块的使用(全面详细)
Python 进阶(五):数据库操作之 SQLite
第77天:Python 操作 SQLite
Python 数据库进阶篇,学习一篇就够了,看完不会你找我
sqlite关闭数据库,清除连接池
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服