藍懿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


發佈了113 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章