蓝懿ios技术交流和心得分享16.1.6

在iOS开发中数据存储的方式可以归纳为两类:一类是存储为文件,另一类是存储到数据库。例如前面IOS开发系列—Objective-C之Foundation框架

的文章中提到归档、plist文件存储,包括偏好设置其本质都是存储为文件,只是说归档或者plist文件存储可以选择保存到沙盒中,而偏好设置系统已经规定只能保存到沙盒的Library/Preferences目录。当然,文件存储并不作为本文的重点内容。本文重点还是说数据库存储,做过数据库开发的朋友应该知道,可以通过SQL直接访问数据库,也可以通过ORM进行对象关系映射访问数据库。这两种方式恰恰对应iOS中SQLite和Core Data的内容,在此将重点进行分析: 

  1. SQLite
  • Core Data
  • FMDB

 

SQLite

SQLite是目前主流的嵌入式关系型数据库,其最主要的特点就是轻量级、跨平台,当前很多嵌入式操作系统都将其作为数据库首选。虽然SQLite是一款轻型数据库,但是其功能也绝不亚于很多大型关系数据库。学习数据库就要学习其相关的定义、操作、查询语言,也就是大家日常说得SQL语句。和其他数据库相比,SQLite中的SQL语法并没有太大的差别,因此这里对于SQL语句的内容不会过多赘述,大家可以参考SQLite中其他SQL相关的内容,这里还是重点讲解iOS中如何使用SQLite构建应用程序。先看一下SQLite数据库的几个特点:

  • 基于C语言开发的轻型数据库 
  • 在iOS中需要使用C语言语法进行数据库操作、访问(无法使用ObjC直接访问,因为libsqlite3框架基于C语言编写) 
  • SQLite中采用的是动态数据类型,即使创建时定义了一种类型,在实际操作时也可以存储其他类型,但是推荐建库时使用合适的类型(特别是应用需要考虑跨平台的情况时) 
  • 建立连接后通常不需要关闭连接(尽管可以手动关闭)

要使用SQLite很简单,如果在Mac OSX上使用可以考虑到SQLite官方网站

下载命令行工具,也可以使用类似于SQLiteManager、Navicat for SQLite等工具。为了方便大家开发调试,建议在开发环境中安装上述工具。

在iOS中操作SQLite数据库可以分为以下几步(注意先在项目中导入libsqlite3框架):

  1. 打开数据库,利用sqlite3_open()

打开数据库会指定一个数据库文件保存路径,如果文件存在则直接打开,否则创建并打开。打开数据库会得到一个sqlite3类型的对象,后面需要借助这个对象进行其他操作。 

  • 执行SQL语句,执行SQL语句又包括有返回值的语句和无返回值语句。 
  • 对于无返回值的语句(如增加、删除、修改等)直接通过sqlite3_exec()

函数执行; 

  • 对于有返回值的语句则首先通过sqlite3_prepare_v2()

进行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

项目目录结构:

运行效果:

Core Data

基本概念

当前,各类应用开发中只要牵扯到数据库操作通常都会用到一个概念“对象关系映射(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”文件。然后在其中创建实体和关系:

模型创建的过程中需要注意:

  • 实体对象不需要创建ID主键,Attributes中应该是有意义属性(创建过程中应该考虑对象的属性而不是数据库中表有几个字段,尽管多数属性会对应表的字段)。 
  • 所有的属性应该指定具体类型(尽管在SQLite中可以不指定),因为实体对象会对应生成ObjC模型类。 
  • 实体对象中其他实体对象类型的属性应该通过Relationships建立,并且注意实体之间的对应关系(例如一个用户有多条微博,而一条微博则只属于一个用户,用户和微博形成一对多的关系)。

以上模型创建后,接下来就是根据上面的模型文件(.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

很显然,通过模型生成类的过程相当简单,通常这些类也不需要手动维护,如果模型发生的变化只要重新生成即可。有几点需要注意:

  • 所有的实体类型都继承于NSManagedObject,每个NSManagedObject对象对应着数据库中一条记录。 
  • 集合属性(例如User中的status)生成了访问此属性的分类方法。 
  • 使用@dynamic代表具体属性实现,具体实现细节不需要开发人员关心。

当然,了解了这些还不足以完成数据的操作。究竟Core Data具体的设计如何,要完成数据的存取我们还需要了解一下Core Data几个核心的类。

  • Persistent Object Store:可以理解为存储持久对象的数据库(例如SQLite,注意Core Data也支持其他类型的数据存储,例如xml、二进制数据等)。 
  • Managed Object Model:对象模型,对应Xcode中创建的模型文件。 
  • Persistent Store Coordinator:对象模型和实体类之间的转换协调器,用于管理不同存储对象的上下文。 
  • Managed Object Context:对象管理上下文,负责实体对象和数据库之间的交互。

Core Data使用

Core Data使用起来相对直接使用SQLite3的API而言更加的面向对象,操作过程通常分为以下几个步骤:

1.创建管理上下文

创建管理上下可以细分为:加载模型文件->指定数据存储路径->创建对应数据类型的存储->创建管理对象上下方并指定存储。 

经过这几个步骤之后可以得到管理对象上下文NSManagedObjectContext,以后所有的数据操作都由此对象负责。同时如果是第一次创建上下文,Core Data会自动创建存储文件(例如这里使用SQLite3存储),并且根据模型对象创建对应的表结构。下图为第一次运行生成的数据库及相关映射文件:

学习ios  重要还是要理清楚思路  在做或者看老师代码的时候 自己多想想为什么  不要自己看着就抄       另外还是要推荐一下 蓝懿IOS这个培训机构  和刘国斌老师刘国斌老师还是很有名气的,听朋友说刘老师成立了蓝懿iOS,,老师讲课方式很独特,能够尽量让每个人都能弄明白,有的比较难懂的地方,如果有的地方还是不懂得话,老师会换个其它方法再讲解,这对于我们这些学习iOS的同学是非常好的,多种方式的讲解会理解得更全面,这个必须得给个赞,嘻嘻,还有就是这里的学习环境很好,很安静,可以很安心的学习,安静的环境是学习的基础,小班讲课,每个班20几个学生,学习氛围非常好,每天都学到9点多才离开教室,练习的时间很充裕,而且如果在练习的过程中有什么困难,随时可以向老师求助,不像其它机构,通过视频教学,有的甚至学完之后都看不到讲师本人,问点问题都不方便,这就是蓝懿与其它机构的区别,相信在刘国斌老师的细心指导下,每个蓝懿学员都能找到满意的工作,加油!

                                                                  写博客第八十八天;

                                                                              QQ:565803433


你可能感兴趣的:(c语言,ios,刘国斌,技术,蓝懿iOS)