1. 程式人生 > >iOS開發系列--資料存取

iOS開發系列--資料存取

 

概覽

在iOS開發中資料儲存的方式可以歸納為兩類:一類是儲存為檔案,另一類是儲存到資料庫。例如前面IOS開發系列—Objective-C之Foundation框架的文章中提到歸檔、plist檔案儲存,包括偏好設定其本質都是儲存為檔案,只是說歸檔或者plist檔案儲存可以選擇儲存到沙盒中,而偏好設定系統已經規定只能儲存到沙盒的Library/Preferences目錄。當然,檔案儲存並不作為本文的重點內容。本文重點還是說資料庫儲存,做過資料庫開發的朋友應該知道,可以通過SQL直接訪問資料庫,也可以通過ORM進行物件關係對映訪問資料庫。這兩種方式恰恰對應iOS中SQLite和Core Data的內容,在此將重點進行分析:

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
    型別的物件,後面需要藉助這個物件進行其他操作。
  2. 執行SQL語句,執行SQL語句又包括有返回值的語句和無返回值語句。
  3. 對於無返回值的語句(如增加、刪除、修改等)直接通過sqlite3_exec()函式執行;
  4. 對於有返回值的語句則首先通過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 <Foundation/Foundation.h>
#import <sqlite3.h>
#import "KCSingleton.h"

@interface KCDbManager : NSObject

singleton_interface(KCDbManager);

#pragma mark - 屬性
#pragma mark 資料庫引用,使用它進行資料庫操作
@property (nonatomic) sqlite3 *database;


#pragma mark - 共有方法
/**
 *  開啟資料庫
 *
 *  @param dbname 資料庫名稱
 */
-(void)openDb:(NSString *)dbname;

/**
 *  執行無返回值的sql
 *
 *  @param sql sql語句
 */
-(void)executeNonQuery:(NSString *)sql;

/**
 *  執行有返回值的sql
 *
 *  @param sql sql語句
 *
 *  @return 查詢結果
 */
-(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 <sqlite3.h>
#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<columnCount; 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的基本操作方法,實現具體的業務邏輯。為了解耦,在控制器中是不會直接接觸資料庫的,控制器中只和模型(模型是領域的抽象)、服務物件有關係,藉助服務層對模型進行各類操作,模型的操作反應到資料庫中就是對錶中資料的操作。具體關係如下:

 MVC

要完成上述功能,首先定義一個應用程式全域性物件進行資料庫、表的建立。為了避免每次都建立資料庫和表出錯,這裡利用了偏好設定進行儲存當前建立狀態(其實這也是資料儲存的一部分),如果建立過了資料庫則不再建立,否則建立資料庫和表。

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 *[email protected]"IsCreatedDb";
    NSUserDefaults *defaults=[[NSUserDefaults alloc]init];
    if ([[defaults valueForKey:key] intValue]!=1) {
        [self createUserTable];
        [self createStatusTable];
        [defaults setValue:@1 forKey:key];
    }
}

+(void)createUserTable{
    NSString *[email protected]"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 *[email protected]"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 <Foundation/Foundation.h>

@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 - 動態方法

/**
 *  初始化使用者
 *
 *  @param name 使用者名稱
 *  @param city 所在城市
 *
 *  @return 使用者物件
 */
-(KCUser *)initWithName:(NSString *)name screenName:(NSString *)screenName profileImageUrl:(NSString *)profileImageUrl mbtype:(NSString *)mbtype city:(NSString *)city;

/**
 *  使用字典初始化使用者物件
 *
 *  @param dic 使用者資料
 *
 *  @return 使用者物件
 */
-(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 <Foundation/Foundation.h>
#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 - 動態方法

/**
 *  初始化微博資料
 *
 *  @param createAt        建立日期
 *  @param source          來源
 *  @param text            微博內容
 *  @param user            傳送使用者
 *
 *  @return 微博物件
 */
-(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user;

/**
 *  初始化微博資料
 *
 *  @param profileImageUrl 使用者頭像
 *  @param mbtype          會員型別
 *  @param createAt        建立日期
 *  @param source          來源
 *  @param text            微博內容
 *  @param userId          使用者編號
 *
 *  @return 微博物件
 */
-(KCStatus *)initWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text userId:(int)userId;
/**
 *  使用字典初始化微博物件
 *
 *  @param dic 字典資料
 *
 *  @return 微博物件
 */
-(KCStatus *)initWithDictionary:(NSDictionary *)dic;

#pragma mark - 靜態方法
/**
 *  初始化微博資料
 *
 *  @param createAt        建立日期
 *  @param source          來源
 *  @param text            微博內容
 *  @param user            傳送使用者
 *
 *  @return 微博物件
 */
+(KCStatus *)statusWithCreateAt:(NSString *)createAt source:(NSString *)source text:(NSString *)text user:(KCUser *)user;
/**
 *  初始化微博資料
 *
 *  @param profileImageUrl 使用者頭像
 *  @param mbtype          會員型別
 *  @param createAt        建立日期
 *  @param source          來源
 *  @param text            微博內容
 *  @param userId          使用者編號
 *
 *  @return 微博物件
 */
+(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 <Foundation/Foundation.h>
#import "KCUser.h"
#import "KCSingleton.h"

@interface KCUserService : NSObject
singleton_interface(KCUserService)

/**
 *  新增使用者資訊
 *
 *  @param user 使用者物件
 */
-(void)addUser:(KCUser *)user;

/**
 *  刪除使用者
 *
 *  @param user 使用者物件
 */
-(void)removeUser:(KCUser *)user;

/**
 *  根據使用者名稱刪除使用者
 *
 *  @param name 使用者名稱
 */
-(void)removeUserByName:(NSString *)name;

/**
 *  修改使用者內容
 *
 *  @param user 使用者物件
 */
-(void)modifyUser:(KCUser *)user;

/**
 *  根據使用者編號取得使用者
 *
 *  @param Id 使用者編號
 *
 *  @return 使用者物件
 */
-(KCUser *)getUserById:(int)Id;

/**
 *  根據使用者名稱取得使用者
 *
 *  @param name 使用者名稱
 *
 *  @return 使用者物件
 */
-(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 <Foundation/Foundation.h>
#import "KCSingleton.h"
@class KCStatus;

@interface KCStatusService : NSObject
singleton_interface(KCStatusService)

/**
 *  新增微博資訊
 *
 *  @param status 微博物件
 */
-(void)addStatus:(KCStatus *)status;

/**
 *  刪除微博
 *
 *  @param status 微博物件
 */
-(void)removeStatus:(KCStatus *)status;

/**
 *  修改微博內容
 *
 *  @param status 微博物件
 */
-(void)modifyStatus:(KCStatus *)status;

/**
 *  根據編號取得微博
 *
 *  @param Id 微博編號
 *
 *  @return 微博物件
 */
-(KCStatus *)getStatusById:(int)Id;

/**
 *  取得所有微博物件
 *
 *  @return 所有微博物件
 */
-(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 *[email protected]"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"];
    [email protected]"上海";
    [[KCUserService sharedKCUserService] modifyUser:user1];
    
    KCUser *user2= [[KCUserService sharedKCUserService]getUserByName:@"Lily"];
    [email protected]"深圳";
    [[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 *[email protected]"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

專案目錄結構:

SQLite3_Directory

執行效果:

SQLite_Weibo

Core Data

基本概念

當前,各類應用開發中只要牽扯到資料庫操作通常都會用到一個概念“物件關係對映(ORM)”。例如在Java平臺使用Hibernate,在.NET平臺使用Entity Framework、Linq、NHibernate等。在iOS中也不例外,iOS中ORM框架首選Core Data,這是官方推薦的,不需要藉助第三方框架。無論是哪種平臺、哪種技術,ORM框架的作用都是相同的,那就是將關係資料庫中的表(準確的說是實體)轉換為程式中的物件,其本質還是對資料庫的操作(例如Core Data中如果儲存型別配置為SQLite則本質還是操作的SQLite資料庫)。細心的朋友應該已經注意到,在上面的SQLite中其實我們在KCMainViewController中進行的資料庫操作已經轉換為了物件操作,服務層中的方法中已經將對資料庫的操作封裝起來,轉換為了對Model的操作,這種方式已經是面向物件的。上述通過將物件對映到實體的過程完全是手動完成的,相對來說操作比較複雜,就拿對KCStatus物件的操作來說:首先要手動建立資料庫(S