在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库。例如前面IOS开发系列—Objective-C之Foundation框架
的文章中提到归档、plist文件存储,包括偏好设置其本质都是存储为文件,只是说归档或者plist文件存储可以选择保存到沙盒中,而偏好设置系统已经规定只能保存到沙盒的Library/Preferences目录。当然,文件存储并不作为本文的重点内容。本文重点还是说数据库存储,做过数据库开发的朋友应该知道,可以通过SQL直接访问数据库,也可以通过ORM进行对象关系映射访问数据库。这两种方式恰恰对应iOS中SQLite和Core Data的内容,在此将重点进行分析:
录
SQLite是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级、跨平台,当前很多嵌入式操作系统都将其作为数据库首选。虽然SQLite是一款轻型数据库,但是其功能也绝不亚于很多大型关系数据库。学习数据库就要学习其相关的定义、操作、查询语言,也就是大家日常说得SQL语句。和其他数据库相比,SQLite中的SQL语法并没有太大的差别,因此这里对于SQL语句的内容不会过多赘述,大家可以参考SQLite中其他SQL相关的内容,这里还是重点讲解iOS中如何使用SQLite构建应用程序。先看一下SQLite数据库的几个特点:
要使用SQLite很简单,如果在Mac OSX上使用可以考虑到SQLite官方网站
下载命令行工具,也可以使用类似于SQLiteManager、Navicat for SQLite等工具。为了方便大家开发调试,建议在开发环境中安装上述工具。
在iOS中操作SQLite数据库可以分为以下几步(注意先在项目中导入libsqlite3框架):
打开数据库会指定一个数据库文件保存路径,如果文件存在则直接打开,否则创建并打开。打开数据库会得到一个sqlite3类型的对象,后面需要借助这个对象进行其他操作。
函数执行;
进行sql语句评估(语法检测),然后通过sqlite3_step()依次取出查询结果的每一行数据,对于每行数据都可以通过对应的sqlite3_column_类型()方法获得对应列的数据,如此反复循环直到遍历完成。当然,最后需要释放句柄。
在整个操作过程中无需管理数据库连接,对于嵌入式SQLite操作是持久连接(尽管可以通过sqlite3_close()
关闭),不需要开发人员自己释放连接。纵观整个操作过程,其实与其他平台的开发没有明显的区别,较为麻烦的就是数据读取,在iOS平台中使用C进行数据读取采用了游标的形式,每次只能读取一行数据,较为麻烦。因此实际开发中不妨对这些操作进行封装:
KCDbManager.h
// // DbManager.h // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
#import
#import
"KCSingleton.h"
@
interface
KCDbManager : NSObject singleton_interface(KCDbManager);
#pragma
mark - 属性
#pragma
mark 数据库引用,使用它进行数据库操作 @
property
(nonatomic) sqlite3 *database;
#pragma
mark - 共有方法
-(
void
)openDb:(NSString *)dbname;
-(
void
)executeNonQuery:(NSString *)sql;
-(NSArray *)executeQuery:(NSString *)sql; @end
KCDbManager.m
// // DbManager.m // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCDbManager.h"
#import
#import
"KCSingleton.h"
#import
"KCAppConfig.h"
#ifndef
kDatabaseName
#define
kDatabaseName @
"myDatabase.db"
#endif
@
interface
KCDbManager() @end @implementation KCDbManager singleton_implementation(KCDbManager)
#pragma
mark 重写初始化方法 -(instancetype)init{ KCDbManager *manager;
if
((manager=[super init])) { [manager openDb:kDatabaseName]; }
return
manager; } -(
void
)openDb:(NSString *)dbname{
//取得数据库保存路径,通常保存沙盒Documents目录
NSString *directory=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]; NSLog(@
"%@"
,directory); NSString *filePath=[directory stringByAppendingPathComponent:dbname];
//如果有数据库则直接打开,否则创建并打开(注意filePath是ObjC中的字符串,需要转化为C语言字符串类型)
if
(SQLITE_OK ==sqlite3_open(filePath.UTF8String, &_database)) { NSLog(@
"数据库打开成功!"
); }
else
{ NSLog(@
"数据库打开失败!"
); } } -(
void
)executeNonQuery:(NSString *)sql{
char
*error;
//单步执行sql语句,用于插入、修改、删除
if
(SQLITE_OK!=sqlite3_exec(_database, sql.UTF8String, NULL, NULL,&error)) { NSLog(@
"执行SQL语句过程中发生错误!错误信息:%s"
,error); } } -(NSArray *)executeQuery:(NSString *)sql{ NSMutableArray *rows=[NSMutableArray
array
];
//数据行 //评估语法正确性
sqlite3_stmt *stmt;
//检查语法正确性
if
(SQLITE_OK==sqlite3_prepare_v2(_database, sql.UTF8String, -1, &stmt, NULL)) {
//单步执行sql语句
while
(SQLITE_ROW==sqlite3_step(stmt)) {
int
columnCount= sqlite3_column_count(stmt); NSMutableDictionary *dic=[NSMutableDictionary dictionary];
for
(
int
i=0; i
const char
*name= sqlite3_column_name(stmt, i);
//取得列名
const unsigned char
*value= sqlite3_column_text(stmt, i);
//取得某列的值
dic[[NSString stringWithUTF8String:name]]=[NSString stringWithUTF8String:(
const char
*)value]; } [rows addObject:dic]; } }
//释放句柄
sqlite3_finalize(stmt);
return
rows; } @end
在上面的类中对于数据库操作进行了封装,封装之后数据操作更加方便,同时所有的语法都由C转换成了ObjC。
下面仍然以微博查看为例进行SQLite演示。当然实际开发中微博数据是从网络读取的,但是考虑到缓存问题,通常会选择将微博数据保存到本地,下面的Demo演示了将数据存放到本地数据库以及数据读取的过程。当然,实际开发中并不会在视图控制器中直接调用数据库操作方法,在这里通常会引入两个概念Model和Service。Model自不必多说,就是MVC中的模型。而Service指的是操作数据库的服务层,它封装了对于Model的基本操作方法,实现具体的业务逻辑。为了解耦,在控制器中是不会直接接触数据库的,控制器中只和模型(模型是领域的抽象)、服务对象有关系,借助服务层对模型进行各类操作,模型的操作反应到数据库中就是对表中数据的操作。具体关系如下:
要完成上述功能,首先定义一个应用程序全局对象进行数据库、表的创建。为了避免每次都创建数据库和表出错,这里利用了偏好设置进行保存当前创建状态(其实这也是数据存储的一部分),如果创建过了数据库则不再创建,否则创建数据库和表。
KCDatabaseCreator.m
// // KCDatabaseCreator.m // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCDatabaseCreator.h"
#import
"KCDbManager.h"
@implementation KCDatabaseCreator +(
void
)initDatabase{ NSString *key=@
"IsCreatedDb"
; NSUserDefaults *defaults=[[NSUserDefaults alloc]init];
if
([[defaults valueForKey:key] intValue]!=1) { [self createUserTable]; [self createStatusTable]; [defaults setValue:@1 forKey:key]; } } +(
void
)createUserTable{ NSString *sql=@
"CREATE TABLE User (Id integer PRIMARY KEY AUTOINCREMENT,name text,screenName text, profileImageUrl text,mbtype text,city text)"
; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } +(
void
)createStatusTable{ NSString *sql=@
"CREATE TABLE Status (Id integer PRIMARY KEY AUTOINCREMENT,source text,createdAt date,\"text\" text,user integer REFERENCES User (Id))"
; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } @end
其次,定义数据模型,这里定义用户User和微博Status两个数据模型类。注意模型应该尽量保持其单纯性,仅仅是简单的POCO,不要引入视图、控制器等相关内容。
KCUser.h
// // KCUser.h // UrlConnection // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
@
interface
KCUser : NSObject
#pragma
mark 编号 @
property
(nonatomic,strong) NSNumber *Id;
#pragma
mark 用户名 @
property
(nonatomic,copy) NSString *name;
#pragma
mark 用户昵称 @
property
(nonatomic,copy) NSString *screenName;
#pragma
mark 头像 @
property
(nonatomic,copy) NSString *profileImageUrl;
#pragma
mark 会员类型 @
property
(nonatomic,copy) NSString *mbtype;
#pragma
mark 城市 @
property
(nonatomic,copy) NSString *city;
#pragma
mark - 动态方法
-(KCUser *)initWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city;
-(KCUser *)initWithDictionary:(NSDictionary *)dic;
#pragma
mark - 静态方法 +(KCUser *)userWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city; @end
KCUser.m
// // KCUser.m // UrlConnection // // Created by Kenshin Cui on 14-3-22. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCUser.h"
@implementation KCUser -(KCUser *)initWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city{
if
(self=[super init]) { self.name=name; self.screenName=screenName; self.profileImageUrl=profileImageUrl; self.mbtype=mbtype; self.city=city; }
return
self; } -(KCUser *)initWithDictionary:(NSDictionary *)dic{
if
(self=[super init]) { [self setValuesForKeysWithDictionary:dic]; }
return
self; } +(KCUser *)userWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city{ KCUser *user=[[KCUser alloc]initWithName:name screenName:screenName profileImageUrl:profileImageUrl mbtype:mbtype city:city];
return
user; } @end
KCStatus.h
// // KCStatus.h // UITableView // // Created by Kenshin Cui on 14-3-1. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
#import
"KCUser.h"
@
interface
KCStatus : NSObject
#pragma
mark - 属性 @
property
(nonatomic,strong) NSNumber *Id;
//微博id
@
property
(nonatomic,strong) KCUser *user;
//发送用户
@
property
(nonatomic,copy) NSString *createdAt;
//创建时间
@
property
(nonatomic,copy) NSString *source;
//设备来源
@
property
(nonatomic,copy) NSString *text;
//微博内容
#pragma
mark - 动态方法
-(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user;
-(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text userId:(
int
)userId;
-(KCStatus *)initWithDictionary:(NSDictionary *)dic;
#pragma
mark - 静态方法
+(KCStatus *)statusWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user;
+(KCStatus *)statusWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text userId:(
int
)userId; @end
KCStatus.m
// // KCStatus.m // UITableView // // Created by Kenshin Cui on 14-3-1. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCStatus.h"
@implementation KCStatus -(KCStatus *)initWithDictionary:(NSDictionary *)dic{
if
(self=[super init]) { [self setValuesForKeysWithDictionary:dic]; self.user=[[KCUser alloc]init]; self.user.Id=dic[@
"user"
]; }
return
self; } -(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user{
if
(self=[super init]) { self.createdAt=createAt; self.source=source; self.text=text; self.user=user; }
return
self; } -(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text userId:(
int
)userId{
if
(self=[super init]) { self.createdAt=createAt; self.source=source; self.text=text; KCUser *user=[[KCUser alloc]init]; user.Id=[NSNumber numberWithInt:userId]; self.user=user; }
return
self; } -(NSString *)source{
return
[NSString stringWithFormat:@
"来自 %@"
,_source]; } +(KCStatus *)statusWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user{ KCStatus *status=[[KCStatus alloc]initWithCreateAt:createAt source:source text:text user:user];
return
status; } +(KCStatus *)statusWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text userId:(
int
)userId{ KCStatus *status=[[KCStatus alloc]initWithCreateAt:createAt source:source text:text userId:userId];
return
status; } @end
然后,编写服务类,进行数据的增、删、改、查操作,由于服务类方法同样不需要过多的配置,因此定义为单例,保证程序中只有一个实例即可。服务类中调用前面封装的数据库方法将对数据库的操作转换为对模型的操作。
KCUserService.h
// // KCUserService.h // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
#import
"KCUser.h"
#import
"KCSingleton.h"
@
interface
KCUserService : NSObject singleton_interface(KCUserService)
-(
void
)addUser:(KCUser *)user;
-(
void
)removeUser:(KCUser *)user;
-(
void
)removeUserByName:(NSString *)name;
-(
void
)modifyUser:(KCUser *)user;
-(KCUser *)getUserById:(
int
)Id;
-(KCUser *)getUserByName:(NSString *)name; @end
KCUserService.m
// // KCUserService.m // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCUserService.h"
#import
"KCUser.h"
#import
"KCDbManager.h"
@implementation KCUserService singleton_implementation(KCUserService) -(
void
)addUser:(KCUser *)user{ NSString *sql=[NSString stringWithFormat:@
"INSERT INTO User (name,screenName, profileImageUrl,mbtype,city) VALUES('%@','%@','%@','%@','%@')"
,user.name,user.screenName, user.profileImageUrl,user.mbtype,user.city]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(
void
)removeUser:(KCUser *)user{ NSString *sql=[NSString stringWithFormat:@
"DELETE FROM User WHERE Id='%@'"
,user.Id]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(
void
)removeUserByName:(NSString *)name{ NSString *sql=[NSString stringWithFormat:@
"DELETE FROM User WHERE name='%@'"
,name]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(
void
)modifyUser:(KCUser *)user{ NSString *sql=[NSString stringWithFormat:@
"UPDATE User SET name='%@',screenName='%@',profileImageUrl='%@',mbtype='%@',city='%@' WHERE Id='%@'"
,user.name,user.screenName,user.profileImageUrl,user.mbtype,user.city,user.Id]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(KCUser *)getUserById:(
int
)Id{ KCUser *user=[[KCUser alloc]init]; NSString *sql=[NSString stringWithFormat:@
"SELECT name,screenName,profileImageUrl,mbtype,city FROM User WHERE Id='%i'"
, Id]; NSArray *rows= [[KCDbManager sharedKCDbManager] executeQuery:sql];
if
(rows&&rows.count>0) { [user setValuesForKeysWithDictionary:rows[0]]; }
return
user; } -(KCUser *)getUserByName:(NSString *)name{ KCUser *user=[[KCUser alloc]init]; NSString *sql=[NSString stringWithFormat:@
"SELECT Id, name,screenName,profileImageUrl,mbtype,city FROM User WHERE name='%@'"
, name]; NSArray *rows= [[KCDbManager sharedKCDbManager] executeQuery:sql];
if
(rows&&rows.count>0) { [user setValuesForKeysWithDictionary:rows[0]]; }
return
user; } @end
KCStatusService.h
// // KCStatusService.h // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
#import
"KCSingleton.h"
@
class
KCStatus; @
interface
KCStatusService : NSObject singleton_interface(KCStatusService)
-(
void
)addStatus:(KCStatus *)status;
-(
void
)removeStatus:(KCStatus *)status;
-(
void
)modifyStatus:(KCStatus *)status;
-(KCStatus *)getStatusById:(
int
)Id;
-(NSArray *)getAllStatus; @end
KCStatusService.m
// // KCStatusService.m // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCStatusService.h"
#import
"KCDbManager.h"
#import
"KCStatus.h"
#import
"KCUserService.h"
#import
"KCSingleton.h"
@
interface
KCStatusService(){ } @end @implementation KCStatusService singleton_implementation(KCStatusService) -(
void
)addStatus:(KCStatus *)status{ NSString *sql=[NSString stringWithFormat:@
"INSERT INTO Status (source,createdAt,\"text\" ,user) VALUES('%@','%@','%@','%@')"
,status.source,status.createdAt,status.text,status.user.Id]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(
void
)removeStatus:(KCStatus *)status{ NSString *sql=[NSString stringWithFormat:@
"DELETE FROM Status WHERE Id='%@'"
,status.Id]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(
void
)modifyStatus:(KCStatus *)status{ NSString *sql=[NSString stringWithFormat:@
"UPDATE Status SET source='%@',createdAt='%@',\"text\"='%@' ,user='%@' WHERE Id='%@'"
,status.source,status.createdAt,status.text,status.user, status.Id]; [[KCDbManager sharedKCDbManager] executeNonQuery:sql]; } -(KCStatus *)getStatusById:(
int
)Id{ KCStatus *status=[[KCStatus alloc]init]; NSString *sql=[NSString stringWithFormat:@
"SELECT Id, source,createdAt,\"text\" ,user FROM Status WHERE Id='%i'"
, Id]; NSArray *rows= [[KCDbManager sharedKCDbManager] executeQuery:sql];
if
(rows&&rows.count>0) { [status setValuesForKeysWithDictionary:rows[0]]; status.user=[[KCUserService sharedKCUserService] getUserById:[(NSNumber *)rows[0][@
"user"
] intValue]] ; }
return
status; } -(NSArray *)getAllStatus{ NSMutableArray *
array
=[NSMutableArray
array
]; NSString *sql=@
"SELECT Id, source,createdAt,\"text\" ,user FROM Status ORDER BY Id"
; NSArray *rows= [[KCDbManager sharedKCDbManager] executeQuery:sql];
for
(NSDictionary *dic in rows) { KCStatus *status=[self getStatusById:[(NSNumber *)dic[@
"Id"
] intValue]]; [
array
addObject:status]; }
return array
; } @end
最后,在视图控制器中调用相应的服务层进行各类数据操作,在下面的代码中分别演示了增、删、改、查四类操作。
KCMainViewController.m
// // KCMainTableViewController.m // DataAccess // // Created by Kenshin Cui on 14-3-29. // Copyright (c) 2014年 Kenshin Cui. All rights reserved. //
#import
"KCMainTableViewController.h"
#import
"KCDbManager.h"
#import
"KCDatabaseCreator.h"
#import
"KCUser.h"
#import
"KCStatus.h"
#import
"KCUserService.h"
#import
"KCStatusService.h"
#import
"KCStatusTableViewCell.h"
@
interface
KCMainTableViewController (){ NSArray *_status; NSMutableArray *_statusCells; } @end @implementation KCMainTableViewController - (
void
)viewDidLoad { [super viewDidLoad]; [KCDatabaseCreator initDatabase];
// [self addUsers]; // [self removeUser]; // [self modifyUserInfo]; // [self addStatus];
[self loadStatusData]; } -(
void
)addUsers{ KCUser *user1=[KCUser userWithName:@
"Binger"
screenName:@
"冰儿"
profileImageUrl:@
"binger.jpg"
mbtype:@
"mbtype.png"
city:@
"北京"
]; [[KCUserService sharedKCUserService] addUser:user1]; KCUser *user2=[KCUser userWithName:@
"Xiaona"
screenName:@
"小娜"
profileImageUrl:@
"xiaona.jpg"
mbtype:@
"mbtype.png"
city:@
"北京"
]; [[KCUserService sharedKCUserService] addUser:user2]; KCUser *user3=[KCUser userWithName:@
"Lily"
screenName:@
"丽丽"
profileImageUrl:@
"lily.jpg"
mbtype:@
"mbtype.png"
city:@
"北京"
]; [[KCUserService sharedKCUserService] addUser:user3]; KCUser *user4=[KCUser userWithName:@
"Qianmo"
screenName:@
"阡陌"
profileImageUrl:@
"qianmo.jpg"
mbtype:@
"mbtype.png"
city:@
"北京"
]; [[KCUserService sharedKCUserService] addUser:user4]; KCUser *user5=[KCUser userWithName:@
"Yanyue"
screenName:@
"炎月"
profileImageUrl:@
"yanyue.jpg"
mbtype:@
"mbtype.png"
city:@
"北京"
]; [[KCUserService sharedKCUserService] addUser:user5]; } -(
void
)addStatus{ KCStatus *status1=[KCStatus statusWithCreateAt:@
"9:00"
source:@
"iPhone 6"
text:@
"一只雪猴在日本边泡温泉边玩iPhone的照片,获得了\"2014年野生动物摄影师\"大赛特等奖。一起来为猴子配个词"
userId:1]; [[KCStatusService sharedKCStatusService] addStatus:status1]; KCStatus *status2=[KCStatus statusWithCreateAt:@
"9:00"
source:@
"iPhone 6"
text:@
"一只雪猴在日本边泡温泉边玩iPhone的照片,获得了\"2014年野生动物摄影师\"大赛特等奖。一起来为猴子配个词"
userId:1]; [[KCStatusService sharedKCStatusService] addStatus:status2]; KCStatus *status3=[KCStatus statusWithCreateAt:@
"9:30"
source:@
"iPhone 6"
text:@
"【我们送iPhone6了 要求很简单】真心回馈粉丝,小编觉得现在最好的奖品就是iPhone6了。今起到12月31日,关注我们,转发微博,就有机会获iPhone6(奖品可能需要等待)!每月抽一台[鼓掌]。不费事,还是试试吧,万一中了呢"
userId:2]; [[KCStatusService sharedKCStatusService] addStatus:status3]; KCStatus *status4=[KCStatus statusWithCreateAt:@
"9:45"
source:@
"iPhone 6"
text:@
"重大新闻:蒂姆库克宣布出柜后,ISIS战士怒扔iPhone,沙特神职人员呼吁人们换回iPhone 4。[via Pan-Arabia Enquirer]"
userId:3]; [[KCStatusService sharedKCStatusService] addStatus:status4]; KCStatus *status5=[KCStatus statusWithCreateAt:@
"10:05"
source:@
"iPhone 6"
text:@
"小伙伴们,有谁知道怎么往Iphone4S里倒东西?倒入的东西又该在哪里找?用了Iphone这么长时间,还真的不知道怎么弄!有谁知道啊?谢谢!"
userId:4]; [[KCStatusService sharedKCStatusService] addStatus:status5]; KCStatus *status6=[KCStatus statusWithCreateAt:@
"10:07"
source:@
"iPhone 6"
text:@
"在音悦台iPhone客户端里发现一个悦单《Infinite 金明洙》,推荐给大家! "
userId:1]; [[KCStatusService sharedKCStatusService] addStatus:status6]; KCStatus *status7=[KCStatus statusWithCreateAt:@
"11:20"
source:@
"iPhone 6"
text:@
"如果sony吧mp3播放器产品发展下去,不贪图手头节目源的现实利益,就木有苹果的ipod,也就木有iphone。柯达类似的现实利益,不自我革命的案例也是一种巨头的宿命。"
userId:2]; [[KCStatusService sharedKCStatusService] addStatus:status7]; KCStatus *status8=[KCStatus statusWithCreateAt:@
"13:00"
source:@
"iPhone 6"
text:@
"【iPhone 7 Plus】新买的iPhone 7 Plus ,如何?够酷炫么?"
userId:2]; [[KCStatusService sharedKCStatusService] addStatus:status8]; KCStatus *status9=[KCStatus statusWithCreateAt:@
"13:24"
source:@
"iPhone 6"
text:@
"自拍神器#卡西欧TR500#,tr350S~价格美丽,行货,全国联保~iPhone6 iPhone6Plus卡西欧TR150 TR200 TR350 TR350S全面到货 招收各种代理![给力]微信:39017366"
userId:3]; [[KCStatusService sharedKCStatusService] addStatus:status9]; KCStatus *status10=[KCStatus statusWithCreateAt:@
"13:26"
source:@
"iPhone 6"
text:@
"猜到猴哥玩手机时所思所想者,再奖iPhone一部。(奖品由“2014年野生动物摄影师”评委会颁发)"
userId:3]; [[KCStatusService sharedKCStatusService] addStatus:status10]; } -(
void
)removeUser{
//注意在SQLite中区分大小写
[[KCUserService sharedKCUserService] removeUserByName:@
"Yanyue"
]; } -(
void
)modifyUserInfo{ KCUser *user1= [[KCUserService sharedKCUserService]getUserByName:@
"Xiaona"
]; user1.city=@
"上海"
; [[KCUserService sharedKCUserService] modifyUser:user1]; KCUser *user2= [[KCUserService sharedKCUserService]getUserByName:@
"Lily"
]; user2.city=@
"深圳"
; [[KCUserService sharedKCUserService] modifyUser:user2]; }
#pragma
mark 加载数据 -(
void
)loadStatusData{ _statusCells=[[NSMutableArray alloc]init]; _status=[[KCStatusService sharedKCStatusService]getAllStatus]; [_status enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { KCStatusTableViewCell *cell=[[KCStatusTableViewCell alloc]init]; cell.status=(KCStatus *)obj; [_statusCells addObject:cell]; }]; NSLog(@
"%@"
,[_status lastObject]); }
#pragma
mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return
1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return
_status.count; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static
NSString *identtityKey=@
"myTableViewCellIdentityKey1"
; KCStatusTableViewCell *cell=[self.tableView dequeueReusableCellWithIdentifier:identtityKey];
if
(cell==nil){ cell=[[KCStatusTableViewCell alloc]initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identtityKey]; } cell.status=_status[indexPath.row];
return
cell; } -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return
((KCStatusTableViewCell *)_statusCells[indexPath.row]).height; } -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return
20.0f; } @end
项目目录结构:
运行效果:
当前,各类应用开发中只要牵扯到数据库操作通常都会用到一个概念“对象关系映射(ORM)”。例如在Java平台使用Hibernate,在.NET平台使用Entity Framework、Linq、NHibernate等。在iOS中也不例外,iOS中ORM框架首选Core Data,这是官方推荐的,不需要借助第三方框架。无论是哪种平台、哪种技术,ORM框架的作用都是相同的,那就是将关系数据库中的表(准确的说是实体)转换为程序中的对象,其本质还是对数据库的操作(例如Core Data中如果存储类型配置为SQLite则本质还是操作的SQLite数据库)。细心的朋友应该已经注意到,在上面的SQLite中其实我们在KCMainViewController中进行的数据库操作已经转换为了对象操作,服务层中的方法中已经将对数据库的操作封装起来,转换为了对Model的操作,这种方式已经是面向对象的。上述通过将对象映射到实体的过程完全是手动完成的,相对来说操作比较复杂,就拿对KCStatus对象的操作来说:首先要手动创建数据库(Status表),其次手动创建模型KCStatus,接着创建服务层KCStatusService。Core Data正是为了解决这个问题而产生的,它将数据库的创建、表的创建、对象和表的转换等操作封装起来,简化了我们的操作(注意Core Data只是将对象关系的映射简化了,并不是把服务层替代了,这一点大家需要明白)。
使用Core Data进行数据库存取并不需要手动创建数据库,这个过程完全由Core Data框架完成,开发人员面对的是模型,主要的工作就是把模型创建起来,具体数据库如何创建则不用管。在iOS项目中添加“Data Model”文件。然后在其中创建实体和关系:
模型创建的过程中需要注意:
以上模型创建后,接下来就是根据上面的模型文件(.xcdatamodeld文件)生成具体的实体类。在Xcode中添加“NSManagedObject Subclass”文件,按照步骤选择创建的模型及实体,Xcode就会根据所创建模型生成具体的实体类。
User.h
// // User.h // CoreData // // Created by Kenshin Cui on 14/03/27. // Copyright (c) 2014年 cmjstudio. All rights reserved. //
#import
#import
@
class
Status; @
interface
User : NSManagedObject @
property
(nonatomic, retain) NSString * city; @
property
(nonatomic, retain) NSString * mbtype; @
property
(nonatomic, retain) NSString * name; @
property
(nonatomic, retain) NSString * profileImageUrl; @
property
(nonatomic, retain) NSString * screenName; @
property
(nonatomic, retain) NSSet *statuses; @end @
interface
User (CoreDataGeneratedAccessors) - (
void
)addStatusesObject:(Status *)value; - (
void
)removeStatusesObject:(Status *)value; - (
void
)addStatuses:(NSSet *)values; - (
void
)removeStatuses:(NSSet *)values; @end
User.m
// // User.m // CoreData // // Created by Kenshin Cui on 14/03/27. // Copyright (c) 2014年 cmjstudio. All rights reserved. //
#import
"User.h"
#import
"Status.h"
@implementation User @dynamic city; @dynamic mbtype; @dynamic name; @dynamic profileImageUrl; @dynamic screenName; @dynamic statuses; @end
Status.h
// // Status.h // CoreData // // Created by Kenshin Cui on 14/03/27. // Copyright (c) 2014年 cmjstudio. All rights reserved. //
#import
#import
@
interface
Status : NSManagedObject @
property
(nonatomic, retain) NSDate * createdAt; @
property
(nonatomic, retain) NSString * source; @
property
(nonatomic, retain) NSString * text; @
property
(nonatomic, retain) NSManagedObject *user; @end
Status.m
// // Status.m // CoreData // // Created by Kenshin Cui on 14/03/27. // Copyright (c) 2014年 cmjstudio. All rights reserved. //
#import
"Status.h"
@implementation Status @dynamic createdAt; @dynamic source; @dynamic text; @dynamic user; @end
很显然,通过模型生成类的过程相当简单,通常这些类也不需要手动维护,如果模型发生的变化只要重新生成即可。有几点需要注意:
当然,了解了这些还不足以完成数据的操作。究竟Core Data具体的设计如何,要完成数据的存取我们还需要了解一下Core Data几个核心的类。
Core Data使用起来相对直接使用SQLite3的API而言更加的面向对象,操作过程通常分为以下几个步骤:
1.创建管理上下文
创建管理上下可以细分为:加载模型文件->指定数据存储路径->创建对应数据类型的存储->创建管理对象上下方并指定存储。
经过这几个步骤之后可以得到管理对象上下文NSManagedObjectContext,以后所有的数据操作都由此对象负责。同时如果是第一次创建上下文,Core Data会自动创建存储文件(例如这里使用SQLite3存储),并且根据模型对象创建对应的表结构。下图为第一次运行生成的数据库及相关映射文件:
学习ios 重要还是要理清楚思路 在做或者看老师代码的时候 自己多想想为什么 不要自己看着就抄 另外还是要推荐一下 蓝懿IOS这个培训机构 和刘国斌老师刘国斌老师还是很有名气的,听朋友说刘老师成立了蓝懿iOS,,老师讲课方式很独特,能够尽量让每个人都能弄明白,有的比较难懂的地方,如果有的地方还是不懂得话,老师会换个其它方法再讲解,这对于我们这些学习iOS的同学是非常好的,多种方式的讲解会理解得更全面,这个必须得给个赞,嘻嘻,还有就是这里的学习环境很好,很安静,可以很安心的学习,安静的环境是学习的基础,小班讲课,每个班20几个学生,学习氛围非常好,每天都学到9点多才离开教室,练习的时间很充裕,而且如果在练习的过程中有什么困难,随时可以向老师求助,不像其它机构,通过视频教学,有的甚至学完之后都看不到讲师本人,问点问题都不方便,这就是蓝懿与其它机构的区别,相信在刘国斌老师的细心指导下,每个蓝懿学员都能找到满意的工作,加油!
写博客第八十八天;
QQ:565803433