IOS Development Series--a detailed introduction to data access _ios

Source: Internet
Author: User
Tags commit object model reserved rollback sqlite sqlite database stmt

Overview

The way data is stored in iOS development can be grouped into two categories: one is stored as a file and the other is stored in a database. For example, the previous iOS development Series-objective-c's foundation framework article mentions archiving, plist file storage, including preferences, which are essentially stored as files, saying that archiving or plist file storage can optionally be saved to a sandbox. The preferences system has already specified that the Library/preferences directory can only be saved to the sandbox. Of course, file storage is not an important part of this article. This article focuses on the database storage, database development friends should know that the database can be directly accessed through SQL, but also through the ORM Object Relationship mapping access to the database. These two methods correspond precisely to the contents of SQLite and core data in iOS, where the focus is analyzed:

    • Sqlite
    • Core Data
    • Fmdb

Sqlite

SQLite is currently the mainstream embedded relational database, its most important feature is lightweight, cross-platform, many embedded operating systems are now the first choice for the database. Although SQLite is a lightweight database, its functionality is no less than that of many large relational databases. Learning a database is to learn its related definitions, operations, query language, that is, everyone daily said SQL statements. The SQL syntax in SQLite is not much different from other databases, so there's no way to repeat the contents of SQL statements, you can refer to other SQL-related content in SQLite, and here's how to use SQLite to build applications in iOS. Take a look at several features of the SQLite database:

    • A lightweight database based on C language development
    • In iOS need to use C language syntax for database operations, access (cannot use OBJC direct access, because the Libsqlite3 framework based on the C language)
    • Dynamic data types are used in SQLite, even when a type is defined at creation time, other types can be stored in the actual operation, but the appropriate type is recommended when building a library (especially when the application needs to consider Cross-platform scenarios)
    • You typically do not need to close a connection after a connection is established (although you can manually turn off)

Using SQLite is very simple, and you can use tools like Sqlitemanager, Navicat for SQLite if you use Mac OS X to consider SQLite web site download command-line tools. In order to facilitate the development of debugging, we recommend that the above tools be installed in the development environment.

Operating the SQLite database in iOS can be divided into the following steps (note that you first import the LIBSQLITE3 framework into your project):

    1. Opening the database, using Sqlite3_open () to open the database specifies a database file save path and opens if the file exists, otherwise it is created and opened. Opening the database will get an object of the Sqlite3 type, which you need to use to do other things with this object.
    2. Executes SQL statements, executes SQL statements, and includes statements with return values and no return value statements.
    3. Statements with no return value (such as additions, deletions, modifications, etc.) are executed directly through the sqlite3_exec () function;
    4. For statements with return values, the SQL statement evaluation (Syntax detection) is first done through SQLITE3_PREPARE_V2 (), then each row of the query results is fetched by Sqlite3_step (), and each row of data can be obtained by corresponding sqlite3_ The Column_ type () method obtains data for the corresponding column so that it repeats until the traversal completes. Finally, of course, you need to release the handle.

Without managing the database connection throughout the operation, the embedded SQLite operation is a persistent connection (although it can be closed via sqlite3_close ()) and the developer does not have to release the connection themselves. Throughout the operation process, in fact, with the development of other platforms there is no obvious difference, the more troublesome is the data read, in the iOS platform using C for data reading using the form of a cursor, each time only read one row of data, more trouble. These operations may therefore be encapsulated in actual development:

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-attribute
#pragma mark database reference, use it for database operations
@property (nonatomic) sqlite3 *database;


#pragma mark-common method
/**
 * Open Database
 *
 * @param dbname Database name * *
-(void) Opendb: (NSString *) dbname;

/**
 * Execute SQL * with no return value (* *
 * @param SQL SQL statement */
(void) ExecuteNonQuery: (NSString *) SQL;

/**
 * Execute SQL * with return value
 *
 @param SQL SQL statement
 * *
 @return Query Results *
 *
(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 &lt;sqlite3.h&gt; #import "KCSingleton.h" #import "KCAppConfig.h" #ifndef Kdatabasena Me #define Kdatabasename @ "mydatabase.db" #endif @interface Kcdbmanager () @end @implementation Kcdbmanager Singleton_
  Implementation (Kcdbmanager) #pragma mark Rewrite initialization method-(instancetype) init{Kcdbmanager *manager;
  if ((Manager=[super init)) {[Manager opendb:kdatabasename];
} return manager; }-(void) Opendb: (NSString *) dbname{//Get the database save path, usually save the sandbox documents directory NSString *directory=[
  Nssearchpathfordirectoriesindomains (NSDocumentDirectory, Nsuserdomainmask, YES) firstobject];
  NSLog (@ "%@", directory);
  NSString *filepath=[directory Stringbyappendingpathcomponent:dbname]; If a database is opened directly, otherwise it is created and opened (note that FilePath is a string in OBJC that needs to be converted to a C-language string type) if (Sqlite_ok ==sqlite3_open filepath.utf8string, &amp;_
db) {NSLog (@ "Database opened successfully!");  }else{NSLog (@ "Database open failed!");}
  -(void) ExecuteNonQuery: (NSString *) sql{char *error; Step through the SQL statement to insert, modify, and delete the IF (sqlite_ok!=sqlite3_exec (_database, SQL). Utf8string, NULL, Null,&amp;error) {NSLog (@) error occurred while executing SQL statement!
  Error message:%s ", error); (Nsarray *) ExecuteQuery: (NSString *) sql{nsmutablearray *rows=[nsmutablearray array];//Data Line//Evaluate syntax correctness SQLite
  3_stmt *stmt; Check for syntax correctness if (SQLITE_OK==SQLITE3_PREPARE_V2 (_database, SQL). Utf8string,-1, &amp;stmt, NULL) {//Single-step SQL statement while (Sqlite_row==sqlite3_step (stmt)) {int columncount= sq
      Lite3_column_count (stmt);
      Nsmutabledictionary *dic=[nsmutabledictionary Dictionary]; for (int i=0; i&lt;columncount; i++) {const char *name= sqlite3_column_name (stmt, I);//Get Column name const Unsigne D Char *value= sqlite3_column_text (stmt, I);//Get the value of a column dic[[nsstring stringwithutf8string:name]]=[nsstring stringWit
      Hutf8string: (const char *) value];
    } [rows Addobject:dic]; }//FreeHandle Sqlite3_finalize (stmt);
return rows;

 } @end

In the above class, the database operation is encapsulated, the data operation is more convenient after encapsulation, and all the syntax is converted from C to OBJC.

The following is still an example of a SQLite demo with a microblog view. Of course, the actual development of micro-blogging data is read from the network, but given the caching problem, usually choose to save the microblogging data to the local, the following demo shows the data to the local database and data reading process. Of course, in actual development, the database operation method is not directly invoked in the view controller, where two concept model and service are usually introduced. Model from needless to say, is in MVC models. and service refers to the operation of the database services layer, it encapsulates the model for the basic operating methods to achieve specific business logic. In order to understand the coupling, in the controller is not directly contact with the database, the controller only and model (model is the domain of abstraction), service objects have relations, with the service layer of the model to carry out various operations, the operation of the model to the database is the operation of the data in the table. The specific relationship is as follows:
To accomplish these functions, first define an application global object for database, table creation. To avoid creating errors every time you create a database and table, you use preferences to save the current creation state (which is also part of the data store), and if you create a database, you will not create it, or you can create a database and a table.

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{Nsstr
  ing *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,screennam
  E 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,creat
  Edat date,\ "text\" Text,user integer REFERENCES User (Id)) ";
[[Kcdbmanager Sharedkcdbmanager] executenonquery:sql];

 } @end

Second, define the data model, which defines the user and microblogging status two data model classes. Note that the model should try to maintain its simplicity, is simply a poco, do not introduce views, controllers and other related content.

KCUser.h

KCUser.h//URLConnection////Created by Kenshin Cui on 14-3-22. Copyright (c) 2014 Kenshin Cui.
All rights reserved. #import &lt;Foundation/Foundation.h&gt; @interface kcuser:nsobject #pragma mark number @property (Nonatomic,strong) NS

Number *id;

#pragma mark user name @property (nonatomic,copy) NSString *name;

#pragma mark user nickname @property (nonatomic,copy) NSString *screenname;

#pragma mark Avatar @property (nonatomic,copy) NSString *profileimageurl;

#pragma mark member Type @property (nonatomic,copy) NSString *mbtype;

#pragma Mark City @property (nonatomic,copy) NSString *city; #pragma mark-Dynamic method/** * Initialize user * * @param name username * @param City Town * * @return User Object/-(Kcuser *) initwithname :(NSString *) name screenname: (NSString *) screenname Profileimageurl: (NSString *) Profileimageurl mbtype: (NSString *)

Mbtype City: (NSString *) city;

/** * Use dictionary to initialize user objects * * @param DIC User Data * * @return User Object * * (Kcuser *) Initwithdictionary: (Nsdictionary *) dic; #pragma mark-static method + (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
  :d IC];
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 &lt;Foundation/Foundation.h&gt; #import "KCUser.h" @interface kcstatus:nsobject #pragma mark-attribute @propert Y (nonatomic,strong) nsnumber *id;//Weibo Id @property (nonatomic,strong) kcuser *user;//Send user @property (nonatomic,copy) NSString *createdat;//Create Time @property (nonatomic,copy) nsstring *source;//device source @property (nonatomic,copy) NSString *text ;//microblogging content #pragma mark-dynamic method/** * Initialize microblogging data * * @param createat Creation Date * @param source * @param text micro Bonnet * @param User Send users * * @return Microblogging Object * * (Kcstatus *) Initwithcreateat: (NSString *) createat Source: (NSString *) so

Urce text: (NSString *) text User: (Kcuser *) user;     /** * Initialization of microblogging data * * @param profileimageurl user avatar * @param mbtype member Type * @param createat created date * @param source SOURCE * @param text microblogging content * @param userId User number * * @return Microblogging object/-(Kcstatus *) InitwiThcreateat: (NSString *) createat Source: (NSString *) source text: (NSString *) text userId: (int) userId;

/** * Using a dictionary to initialize the microblogging object * * @param dic Dictionary data * * @return Microblogging Object * * (Kcstatus *) Initwithdictionary: (Nsdictionary *) dic; #pragma mark-static method/** * Initialize micro-bo data * * @param createat Creation Date * @param source * @param text microblogging content * @para M User Send users * * @return Microblogging object/+ (Kcstatus *) Statuswithcreateat: (NSString *) createat Source: (NSString *) source Tex
T: (NSString *) text User: (Kcuser *) user;     /** * Initialization of microblogging data * * @param profileimageurl user avatar * @param mbtype member Type * @param createat created date * @param source SOURCE * @param text microblogging content * @param userId User number * * @return Microblogging Object * * + (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:@ "from%@", _source];} + (Kcstatus *) Statuswithcreateat: (NSString *) createat Source: (NSString *) source text: (NSString *) text User: (Kcuser *)
  user{kcstatus *status=[[kcstatus alloc]initwithcreateat:createat source:source Text:text];
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];
return status;

 } @end

Then, the writing service class, the data increase, delete, change, check operation, because the service class method also does not need too much configuration, so defined as a single example, guarantee program only one instance can. The database method called in the previous encapsulation in the service class converts the operation of the database to the operation of the model.

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)

/**
 * Add user Information
 *
 * @param user User Object */
-(void) AddUser: (Kcuser *) user;

/** *
 Delete User
 *
 * @param user Object/
-(void) Removeuser: (Kcuser *) users;

/**
 * Delete User by user name
 *
 * @param name User name * *
-(void) Removeuserbyname: (NSString *) name;

/**
 * Modify User Content
 *
 * @param user Object/
-(void) ModifyUser: (Kcuser *) user;

/**
 * According to the user number of user * * *
 @param Id User Number
 * *
 @return User Object * *
-(Kcuser *) Getuserbyid: ( int) Id;

/** * User Name * * *
 @param name
 username * *
 @return User Object * *
(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_impleme Ntation (Kcuserservice)-(void) AddUser: (Kcuser *) user{nsstring *sql=[nsstring ' stringwithformat:@ ' INSERT into user (Nam E,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&amp;&amp;rows.count&gt;0) {[user setvaluesforkeyswithdictionary:rows[0]];
return to 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&amp;&amp;rows.count&gt;0) {[User setvaluesforkeyswIthdictionary:rows[0]];
return to 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)

/**
 * Add microblogging information
 *
 * @param status Micro-bo Object * *
(void) Addstatus: (Kcstatus *) status;

/** *
 Delete micro bo
 *
 * @param status Microblogging Object *
 *
(void) Removestatus: (Kcstatus *) status;

/**
 * Modify microblogging content *
 * @param status micro-Bo object
 /
-(void) Modifystatus: (Kcstatus *) status;

/** *
 based on the number of micro-bo
 * *
 * @param Id Weibo number
 * *
 @return Micro-bo object
/-(Kcstatus *) Getstatusbyid: ( int) Id;

/**
 * Obtain all Micro Bo objects
 *
 * @return all micro-Blog Objects * *
(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 "Kcsinglet 


On.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= '%@ ', cre atedat= '%@ ', \ "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&amp;&amp;rows.count&gt;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

Finally, in the view controller call the corresponding service layer for various types of data operations, in the following code to demonstrate the increase, delete, change, check four types of operations.

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:@ "ice Son" profileimageurl:@ "Binger.jpg" Mbtype
  : @ "mbtype.png" city:@ "Beijing"];
  [[Kcuserservice Sharedkcuserservice] adduser:user1]; Kcuser *user2=[kcuser userwithname:@ "Xiaona" screenname:@ "Natalie" ProFileimageurl:@ "Xiaona.jpg" mbtype:@ "Mbtype.png" city:@ "Beijing"];
  [[Kcuserservice Sharedkcuserservice] adduser:user2]; Kcuser *user3=[kcuser userwithname:@ "Lily screenname:@" Lily "profileimageurl:@" lily.jpg "mbtype:@" Mbtype.png "city:@"
  Beijing "];
  [[Kcuserservice Sharedkcuserservice] adduser:user3]; Kcuser *user4=[kcuser userwithname:@ "Qianmo" screenname:@ "Criss" profileimageurl:@ "qianmo.jpg" mbtype:@ "Mbtype.png"
  city:@ "Beijing"];
  [[Kcuserservice Sharedkcuserservice] adduser:user4]; Kcuser *user5=[kcuser userwithname:@ "Yanyue" screenname:@ "Inflammatory month" profileimageurl:@ "yanyue.jpg" mbtype:@ "Mbtype.png"
  city:@ "Beijing"];
[[Kcuserservice Sharedkcuserservice] adduser:user5]; }-(void) addstatus{kcstatus *status1=[kcstatus statuswithcreateat:@ "9:00" source:@ "IPhone 6" text:@ " A snow monkey at the Japanese side bubble hot spring to play the iphone photo, won the "2014 Wildlife photographer \" grand prize.
  Together for monkeys with a word "userid:1];"
  [[Kcstatusservice Sharedkcstatusservice] addstatus:status1]; Kcstatus *status2=[kcstatus statuswithcreateat:@ "9:00" source:@ "iphone 6" text:@ "A snow monkey plays the IPhone on the edge of a hot spring in Japan.Film, won the "2014 Wildlife photographer \" grand prize.
  Together for monkeys with a word "userid:1];"
  [[Kcstatusservice Sharedkcstatusservice] addstatus:status2]; Kcstatus *status3=[kcstatus statuswithcreateat:@ "9:30" source:@ "IPhone 6" text:@ "" We sent IPhone6 the request is very simple "really give back to the fans, Xiao Bian think the best prize now is iPhone6. Today to December 31, pay attention to us, forward Weibo, there will be a chance to get IPhone6 (prizes may need to wait)! Draw one each month [applause].
  No trouble, or try it, in case of the "userid:2];"
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS3]; Kcstatus *status4=[kcstatus statuswithcreateat:@ "9:45" source:@ "the iphone 6" text:@ "major news: After Tim Cook temporarily announced the Cabinet, ISIS fighters angrily threw the iphone, Saudi clerics urge people to change back to iphone 4.
  [Via Pan-arabia Enquirer] "userid:3];
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS4]; Kcstatus *status5=[kcstatus statuswithcreateat:@ "10:05" source:@ "IPhone 6" text:@ "Little friends, who knows how to pour things into iphone4s? Where should I find the stuff I poured into? With the iphone for such a long time, I really do not know how to get! Who knows? Thank you!
  "Userid:4];
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS5]; Kcstatus *status6=[kcstatus statuswithcreateat:@ "10:07" source:@ "iphone 6" text:@ "found a single" Infinite Kimming "in the Music Hyatt iphone client , recommend to everyone!
  "Userid:1]; [[KcstaTusservice Sharedkcstatusservice] ADDSTATUS:STATUS6]; Kcstatus *status7=[kcstatus statuswithcreateat:@ "11:20" source:@ "IPhone 6" text:@ "if Sony MP3 player product development, do not covet the real interest of the program source at hand , with an Apple ipod and a wooden iphone. Kodak similar practical interests, not self-revolutionary case is also a giant's fate.
  "Userid:2];
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS7]; Kcstatus *status8=[kcstatus statuswithcreateat:@ "13:00" source:@ "iphone 6" text:@ "iphone 7 Plus" the new iphone 7 Plus, how? Cool enough?
  "Userid:2];
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS8]; Kcstatus *status9=[kcstatus statuswithcreateat:@ "13:24" source:@ "IPhone 6" text:@ "Self-portrait artifact # Casio tr500#,tr350s~ price beautiful, licensed, National UNPROFOR ~iphone6 iphone6plus Casio TR150 TR200 TR350 tr350s Comprehensive arrival to recruit a variety of agents!
  [To force] micro-letter: 39017366 "Userid:3];
  [[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS9]; Kcstatus *status10=[kcstatus statuswithcreateat:@ "13:26" source:@ "iphone 6" text:@ "guessed that monkey brother is playing mobile phone when the thought of the next award for the iphone."
  (Awarded by the "2014 Wildlife Photographer" jury) "Userid:3";
[[Kcstatusservice Sharedkcstatusservice] ADDSTATUS:STATUS10];
}-(void) removeuser{  Note the case sensitivity in sqlite [[Kcuserservice Sharedkcuserservice] removeuserbyname:@ "Yanyue"];
  }-(void) modifyuserinfo{kcuser *user1= [[Kcuserservice sharedkcuserservice]getuserbyname:@ "Xiaona"];
  user1.city=@ "Shanghai";
  
  [[Kcuserservice Sharedkcuserservice] modifyuser:user1];
  Kcuser *user2= [[Kcuserservice sharedkcuserservice]getuserbyname:@ "Lily"];
  user2.city=@ "Shenzhen";
[[Kcuserservice Sharedkcuserservice] modifyuser:user2];
  #pragma mark loading Data-(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

Project directory Structure:

Operation Effect:

Core Data

Basic concepts

At present, a concept "Object relational Mapping (ORM)" is usually used in all kinds of application development as long as the database operation is involved. For example, using Hibernate on the Java platform, use the entity Framework, LINQ, NHibernate, etc. on the. NET platform. In iOS is no exception, iOS in the ORM Framework preferred core Data, which is officially recommended, do not need to rely on third-party frameworks. Regardless of the platform or the technology, the ORM framework works the same way, which is to convert a table in a relational database (which is an exact entity) into an object in a program, essentially an operation on a database (for example, the core In data, if the storage type is configured as SQLite, it is essentially an operational SQLite database. Careful friend should have noticed, in the above SQLite in fact our database operation in Kcmainviewcontroller has been converted to object operation, the method in the service layer has already encapsulated the operation of the database, transforms for the operation of model, This approach is already object-oriented. The process of mapping an object to an entity is completely manual and relatively complex, taking action on a Kcstatus object: First you create the database manually (the status table), and then manually create the model Kcstatus. Next, create the service layer Kcstatusservice. Core data was created to solve this problem, it encapsulates the creation of databases, the creation of tables, the transformation of objects and tables, and simplifies our operations (note that core data simply simplifies the mapping of object relationships and does not replace the service layer, which you need to understand).

Using core data for database access does not require the creation of a database manually, this process is entirely done by the core data framework, developers are faced with the model, the main task is to create the model, the specific database how to create without the control. Add the "Data Model" file to the iOS project. Then create entities and relationships in them:

The process of creating a model requires attention:

    • The entity object does not need to create an ID primary key, which should be a meaningful attribute (you should consider the properties of the object during the creation process rather than the tables in the database, although most of the properties will correspond to the table's fields). Attributes
    • All properties should specify a specific type (although it may not be specified in SQLite) because the entity object corresponds to the build OBJC model class.
    • Attributes of other entity object types in an entity object should be established through relationships, and attention should be paid to the correspondence between entities (for example, a user has multiple tweets, and a microblog is only one user, and the user and Weibo form a one-to-many relationship).

After the above model is created, the next step is to generate a specific entity class from the model file (. xcdatamodeld file) above. Add the Nsmanagedobject subclass file to the Xcode, follow the steps to select the model and entity that you created, and Xcode generate concrete entity classes based on the model you created.

User.h


//User.h
//CoreData////
Created by Kenshin Cui on 14/03/27.
Copyright (c) 2014 Cmjstudio. All rights reserved.

#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>

@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 <Foundation/Foundation.h>
#import <CoreData/CoreData.h>


@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

Obviously, the process of generating classes through a model is fairly simple, and usually these classes do not need to be manually maintained, if the model changes occur as long as they are regenerated. There are a few things to note:

    • All entity types inherit from Nsmanagedobject, and each Nsmanagedobject object corresponds to a record in the database.
    • Collection properties, such as status in user, generate a classification method that accesses this property.
    • Using @dynamic represents the implementation of a specific attribute, and implementation details do not require the developer's attention.

Of course, it's not enough to get the data done. Exactly how the core data is designed and the data accessed we also need to know the core data cores of the classes.

    • Persistent Object Store: a database that can be understood to store persistent objects (such as sqlite, note that core data also supports other types of data storage, such as XML, binary data, and so on).
    • Managed Object Model: The model file that corresponds to the Xcode created in the.
    • Persistent Store Coordinator: a transformation coordinator between an object model and an entity class that manages the context of different storage objects.
    • Managed Object Context: Objects manage contexts, which are responsible for interaction between entity objects and databases.

Core Data usage

Core data is more object-oriented than using the SQLite3 API directly, and the process is usually divided into the following steps:

1. Create an administrative context

Create management can be divided into: Load model file-> Specify the data store path-> create a corresponding data type of storage-> the creation of a management object below and specify storage.

After these steps, you can get the Admin object Context Nsmanagedobjectcontext, and all subsequent data operations are responsible for this object. At the same time, if the context is created for the first time, Core data automatically creates a storage file (for example, using SQLite3 storage) and creates a corresponding table structure based on the model object. The following figure is the first time a generated database and related mapping file is run:
For ease of use later, the Nsmanagedobjectcontext object can be saved as a single or static property, and the following is the main code for the Admin object context that is created:

-(Nsmanagedobjectcontext *) createdbcontext{nsmanagedobjectcontext *context;
  Open the model file, and the parameter is nil to open all the model files in the package and merge into a nsmanagedobjectmodel *model=[nsmanagedobjectmodel Mergedmodelfrombundles:nil]; Create parser Nspersistentstorecoordinator *storecoordinator=[[nspersistentstorecoordinator Alloc]
  Initwithmanagedobjectmodel:model]; Create a database save path nsstring *dir=[nssearchpathfordirectoriesindomains (nsdocumentdirectory, Nsuserdomainmask, YES)
  Firstobject];
  NSLog (@ "%@", dir);
  NSString *path=[dir stringbyappendingpathcomponent:@ "mydatabase.db"];
  Nsurl *url=[nsurl Fileurlwithpath:path];
  Add SQLite persistent storage to parser nserror *error; [Storecoordinator addpersistentstorewithtype:nssqlitestoretype configuration:nil URL:url options:nil error:&amp;
  ERROR]; The IF (error) {NSLog (@) database failed to open!
  Error:%@ ", error.localizeddescription);
    }else{Context=[[nsmanagedobjectcontext Alloc]init];
    Context.persistentstorecoordinator=storecoordinator; NSLog (@ "database opened successfully!)
  ");
return to context;
 }

2. Query data

For conditional queries, the core data is implemented by predicates. First creates a request, then sets the request condition, and finally invokes the method that the context executes the request.

-(void) Adduserwithname: (NSString *) name screenname: (NSString *) screenname Profileimageurl: (NSString *) Profileimageurl Mbtype: (NSString *) Mbtype City: (NSString *) city{
  //Add an object
  User *us= [nsentitydescription insertnewobjectforentityforname:@ "User" inManagedObjectContext:self.context];
  Us.name=name;
  Us.screenname=screenname;
  Us.profileimageurl=profileimageurl;
  Us.mbtype=mbtype;
  us.city=city;
  Nserror *error;
  Save Context
  if (![ Self.context Save:&error]) {
    NSLog error occurred during add (@), error message:%@! ", error.localizeddescription);
  }

If you have more than one condition, just use a combination of predicates, so how do you query for the associated object condition? Here are two kinds of situations to introduce:

A. Find a single object with only one associated object, for example, to find a microblog with a user named "Binger" (a microblog can only belong to one user), through the KeyPath query

-(Nsarray *) Getstatusesbyusername: (NSString *) name{
  nsfetchrequest *request=[nsfetchrequest fetchrequestwithentityname:@ "Status"];
  Request.predicate=[nspredicate predicatewithformat:@ "user.name=%@", name];
  Nsarray *array=[self.context executefetchrequest:request Error:nil];
  return array;
}

If you trace the SQL statement generated by core data, you will find that the status table and the user table are associated with the query (join join).

B. Find cases where an object has multiple associated objects, such as finding a user with a "Watch" in the sent microblogging content and a user with a nickname of "Natalie" (a user with multiple tweets) that can be filtered using predicates.

-(Nsarray *) Getstatusesbyusername: (NSString *) name{
  nsfetchrequest *request=[nsfetchrequest fetchrequestwithentityname:@ "Status"];
  Request.predicate=[nspredicate predicatewithformat:@ "user.name=%@", name];
  Nsarray *array=[self.context executefetchrequest:request Error:nil];
  return array;
}

Note If you simply look for a user with a "Watch" in your microblog, you can find the corresponding microblog directly, and then use the user attribute of each microblog to obtain the users, without using the additional predicate filtering conditions.

3. Inserting data

Inserting data requires calling the entity Description Object Nsentitydescription returns an entity object, then sets the object properties, and finally saves the current context. Here need attention, add, delete, change operation end must call the Management object context save method, otherwise the operation will not execute.

-(void) Adduserwithname: (NSString *) name screenname: (NSString *) screenname Profileimageurl: (NSString *) Profileimageurl Mbtype: (NSString *) Mbtype City: (NSString *) city{
  //Add an object
  User *us= [nsentitydescription insertnewobjectforentityforname:@ "User" inManagedObjectContext:self.context];
  Us.name=name;
  Us.screenname=screenname;
  Us.profileimageurl=profileimageurl;
  Us.mbtype=mbtype;
  us.city=city;
  Nserror *error;
  Save Context
  if (![ Self.context Save:&error]) {
    NSLog error occurred during add (@), error message:%@! ", error.localizeddescription);
  }

4. Delete data

Deleting data can directly invoke the DeleteObject method that manages the object context, and the save context is removed. Note that you must first query the corresponding object before you delete the data.

-(void) Removeuser: (User *) user{
  [Self.context deleteobject:user];
  Nserror *error;
  if (![ Self.context Save:&error]) {
    NSLog (@ "error occurred during deletion, error message:%@!", error.localizeddescription);
  }

5. Modify Data

Modifying the data first is also to take out the corresponding entity object and then save the context by modifying the object's properties.

-(void) Modifyuserwithname: (NSString *) name screenname: (NSString *) screenname Profileimageurl: (NSString *) Profileimageurl Mbtype: (NSString *) Mbtype City: (NSString *) city{
  User *us=[self getuserbyname:name];
  Us.screenname=screenname;
  Us.profileimageurl=profileimageurl;
  Us.mbtype=mbtype;
  us.city=city;
  Nserror *error;
  if (![ Self.context Save:&error]) {
    NSLog (@ "error occurred during modification, error message:%@", error.localizeddescription);
  }


Debugging

Although Core Data (if used SQLite database) operations are eventually converted to SQL operations, debugging is not as convenient as operating SQL. Especially for beginners often appear query error, if you can see the resulting SQL statement naturally for debugging is very helpful. In fact, in the Xcode is to support core data debugging, the specific operation: Product-scheme-edit Scheme-run-arguments Add two parameters (note that the parameter order can not be wrong):-com.apple.coredata.sqldebug, 1. The SQL statement is then printed in the output panel if the database is manipulated during the run of the program.
Note: If the model changes, the entity class files can be rebuilt at this time, but the generated database is not automatically updated, and you need to consider rebuilding the database and migrating the original data.

Fmdb

Basic use

Compared to SQLite3, core data has many advantages, it is object-oriented, developers do not have to care too much about the knowledge of database operations, and it is based on OBJC operations, writing more elegant and so on. But it also has certain limitations, for example, if you consider Cross-platform, you can only choose SQLite, because both iOS and Android can use the same database, reduce development costs and maintenance costs. The second is the performance problem of most ORM frameworks, because ORM eventually translates into SQL operations, involving model data conversions, which are naturally less performance than using SQL operations databases directly. So is there a better choice? The answer is to encapsulate the SQLite.

In fact, through the previous analysis of SQLite, we should have seen Kcdbmanager is the result of the SQLite package, developers face only the SQL and OBJC methods, not too much libsqlite3 of the C language API. But it is only a simple encapsulation, there are more details not considered, such as how to deal with concurrent security, how to better deal with the transaction and so on. Therefore, it is recommended to use a Third-party framework Fmdb, the entire framework is very lightweight but without losing flexibility, but also a lot of enterprise development preferred.

1.FMDB since it is the encapsulation of the LIBSQLITE3 framework, it is similar to use naturally, open a database before use, the database file exists directly open otherwise will be created and opened. Here Fmdb introduces a Fmdatabase object to represent the database, open the database and subsequent database operations all rely on this object. Here's the code to open the database to get the Fmdatabase object:

-(void) Opendb: (NSString *) dbname{
  //Get the database save path, usually save the sandbox documents directory
  NSString *directory=[ Nssearchpathfordirectoriesindomains (NSDocumentDirectory, Nsuserdomainmask, YES) firstobject];
  NSLog (@ "%@", directory);
  NSString *filepath=[directory Stringbyappendingpathcomponent:dbname];
  Create Fmdatabase Object
  self.database=[fmdatabase Databasewithpath:filepath];
  Open the data on the
  if ([Self.database Open]) {
    NSLog (@ Database open successfully!);
  } else{
    NSLog (@ "Database open failed!");
  }

Note: The path parameters in Datawithpath generally choose to be saved to the documents directory in the sandbox, and if this parameter is set to nil, the database is created in memory, and if set to @, the file is deleted in the temporary directory in the sandbox, and the application closes.

2. The operation of the database is similar to that of the previous Kcdbmanager, in Fmdb fmdatabase classes provide two methods executeupdate: and ExecuteQuery: For queries that do not return results and for queries that have returned results, respectively. Of course these two methods have a lot of overloading here is not explained in detail. The only thing to point out is that if you call an SQL statement that has a format parameter, the formatting symbol uses the "?" Rather than "%@" and so on. The following are code snippets for two scenarios:

A. No return results

-(void) ExecuteNonQuery: (NSString *) sql{
  //Execute UPDATE SQL statement for inserting, modifying, deleting
  if (![ Self.database Executeupdate:sql]) {
    NSLog (@) error occurred while executing SQL statement! ");
  }
}

B. There are return results

-(Nsarray *) ExecuteQuery: (NSString *) sql{
  nsmutablearray *array=[nsmutablearray array];
  Execute query SQL statement
  fmresultset *result= [self.database executequery:sql];
  while (Result.next) {
    nsmutabledictionary *dic=[nsmutabledictionary dictionary];
    for (int i=0; i<result.columncount; ++i) {
      dic[[result columnnameforindex:i]]=[result stringforcolumnindex:i] ;
    }
    [Array addobject:dic];
  }
  return array;
}

For queries with return results, the query returns a cursor Fmresultset, which is queried by traversing the cursor. In addition, Fmdb provides a large number of intforcolumn, Stringforcolumn and other methods to take value.

Concurrency and transactions

We know that the direct use of Libsqlite3 for database operations is actually thread-unsafe, and unexpected results may occur if multiple threads are encountered simultaneously manipulating a table. To solve this problem, it is recommended that you use the Fmdatabasequeue object in multiple threads, which is thread-safe compared to fmdatabase.

The method for creating fmdatabasequeue is similar, calling Databasequeuewithpath: method. Note that you do not need to invoke the open operation here.

-(void) Opendb: (NSString *) dbname{
  //Get the database save path, usually save the sandbox documents directory
  NSString *directory=[ Nssearchpathfordirectoriesindomains (NSDocumentDirectory, Nsuserdomainmask, YES) firstobject];
  NSLog (@ "%@", directory);
  NSString *filepath=[directory Stringbyappendingpathcomponent:dbname];
  Create Fmdatabasequeue Object
  self.database=[fmdatabasequeue Databasequeuewithpath:filepath];
}

And then all the additions and deletions to the operation call Fmdatabasequeue's Indatabase: Method executes the operation SQL statement in the block.

-(void) ExecuteNonQuery: (NSString *) sql{//execute an UPDATE SQL statement for inserting, modifying, deleting [Self.database indatab
  ase:^ (Fmdatabase *db) {[db executeupdate:sql];
}];
  }-(Nsarray *) ExecuteQuery: (NSString *) sql{nsmutablearray *array=[nsmutablearray array]; [Self.database indatabase:^ (Fmdatabase *db)
    {//Execute query SQL statement fmresultset *result= [DB executequery:sql];
      while (Result.next) {nsmutabledictionary *dic=[nsmutabledictionary dictionary];
      for (int i=0; i<result.columncount; ++i) {dic[[result columnnameforindex:i]]=[result stringforcolumnindex:i];
    } [array addobject:dic];
  }
  }];
return array; }

The reason for putting a transaction into Fmdb is not because only Fmdb supports the transaction, but because Fmdb encapsulates it into several methods to invoke without writing the corresponding SQL. In fact, when using Libsqlite3 to manipulate a database, it is also a native support transaction (since the transaction here is based on a database, Fmdb, or SQLite database), as long as you precede the execution of the SQL statement with the "BEGIN Transaction;" Execute "COMMIT transaction" after execution; or "ROLLBACK TRANSACTION." Commit or rollback. In addition, in the core data you can also find that all of the add, delete, change operation must call the context of the Save method, in fact, itself provides a transaction support, as long as the Save method is not invoked, all previous operations are not submitted. In Fmdb, Fmdatabase has BeginTransaction, commit, and rollback three methods for opening transactions, committing transactions, and rolling back transactions.

Original link: http://www.cnblogs.com/kenshincui/p/4077833.html

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.