iOS中使用的是sqlite3数据库,操作数据库的时候首先需要会数据库操作语句—sql语句,在代码中操作数据库时,可以先利用其它数据库软件编写sql语句并验证是否正确(相关软件:Navicat Premium)
基本知识
数据库操作sql基本语句
-- SQL语法
-- 单行注释
/*多行注释*/
-- 不区分大小写
-- 每条语句后面加;
-- 字符串以''括起来
-- 字段类型:text -> 字符串类型 integer -> 整型 real -> 浮点型
-- DDL语句
-- 1.创建表
-- 格式1:CREATE TABLE 表名(字段名1 字段1类型,字段名2 字段2类型,...)
-- CREATE TABLE t_Student('name' text,'age' integer,'score' real);
-- 格式2(常用):CREATE TABLE IF NOT EXISTS 表名(字段名1 字段1类型,字段名2 字段2类型,...)
-- CREATE TABLE IF NOT EXISTS t_Student(name text,age integer,score real);
-- 完整的创建表的示例:(必须设置主键)
CREATE TABLE
IF NOT EXISTS t_Student (
id integer PRIMARY KEY AUTOINCREMENT,
name text NOT NULL,
age integer DEFAULT 18,
studyId integer UNIQUE,
score real
);
-- 2.删除表
-- 格式1:DROP TABLE 表名
-- DROP TABLE t_Student;
-- 格式2(常用):DROP TABLE IF EXISTS 表名
-- DROP TABLE IF EXISTS t_Student;
-- DML语句
-- 1.插入数据:INSERT INTO 表名(字段名1,字段名2,...) VALUES(字段1的值,字段2的值,...)
-- INSERT INTO t_Student(name,age,score) VALUES('小明',20,90);
-- INSERT INTO t_Student(name,age,score) VALUES('小红',22,89);
-- INSERT INTO t_Student(name,age,score) VALUES('小芳',23,96);
INSERT INTO t_Student(name,age,score,studyId) VALUES('小明',10,98,160501)
-- 2.修改数据
-- 格式:UPDATE 表名 SET 字段名1=字段1的新值,字段名2=字段2的新值,...
-- UPDATE t_Student SET 'age'=18; --注意:这样写所有数据的age都会变成18
-- 将表中'小明'的年龄改成18
-- UPDATE t_Student SET age = 18 WHERE name = '小明';
-- 3.删除数据
-- 格式:DELETE FROM 表名
-- DELETE FROM t_Student; --注意:这样是删除表中所有的数据
-- 删除成绩小于90的学生
-- DELETE FROM t_Student WHERE score < 90;
-- DQL语句
-- 1.查询数据
-- 格式1:SELECT 字段名1,字段名2,... FROM 表名(字段名不能用''括起来)
-- SELECT name,score FROM t_Student; -- 查询指定字段的数据
-- 格式2:SELECT * FROM 表名
-- SELECT * FROM t_Student; -- 查询表中所有的数据
-- 获取表中年龄大于20且成绩小于90的学生的信息
-- SELECT * FROM t_Student WHERE age > 20 AND score < 90;
-- 2.获取表中的数据的个数
-- 格式1:SELECT count(*) FROM 表名
-- SELECT count(*) FROM t_Student;
-- 查询成绩小于90的学生的数量
-- SELECT count(*) FROM t_Student WHERE score < 90;
-- 3.对查询结果进行排序
-- 格式:SELECT * FROM 表名 ORDER BY 字段名 升序/降序
-- SELECT * FROM t_Student ORDER BY score; (默认asc升序)
-- SELECT * FROM t_Student ORDER BY score DESC;(降序)
-- 4.限制查询的结果的数量
-- 格式:SELECT * FROM 表名 LIMIT 数值1,数值2(跳过数值1条数据[从第0条开始数],每次查询数值2条数据)
-- SELECT * FROM t_Student LIMIT 1,2;
Swift利用OC第三方库FMDB数据库操作
在OC中可以直接使用系统的sqlite3库文件进行数据库操作,在swift中直接操作sqlite3需要从c语言层进行封装,比较复杂,所以在swift中使用FMDB(实质是OC的第三方库)来操作数据库,FMDB是基于sqlite3进行封装,所以在使用的时候需要在工程中导入sqlite3库文件
Swift操作数据库需要用到OC的第三方库FMDB(如何使用第三方库请看下方的跳转),在使用sqlite3时要先调用sqlite3,然后在桥接文件导入sqlite3.h
如何使用第三方库
传送门:http://www.jianshu.com/p/734f7b1280f3
数据库操作步骤:
1.创建数据库对象并打开数据库
2.创建表
3.数据的增删改查
注意:
数据库的所有操作都必须在数据库打开的前提下进行
import UIKit
//在OC中可以直接使用系统的sqlite3库文件进行数据库操作,在swift中直接操作sqlite3需要从c语言层进行封装,所以在swift中使用FMDB(实质是OC的第三方库)来操作数据库
//FMDB是基于sqlite3进行封装,所以在使用的时候需要在工程中导入sqlite3库文件
//数据库操作步骤:
//注意:数据库的所有操作都必须在数据库打开的前提下进行
//1.创建数据库对象并打开数据库
//2.创建表
//3.数据的增删改查
class ViewController: UIViewController {
//MARK: - 属性
//1.数据库
lazy var db: FMDatabase = {
//创建数据库对象(实质是将本地数据库文件和数据库对象关联)
//参数:数据库文件的路径(实际开发中是沙盒下的路径)后缀是.sqlite或者.db
//如果参数关联的数据库文件存在就直接关联,不存在就自动创建
let tdb = FMDatabase(path: "/Users/IOS1605/Desktop/user.sqlite")//按自己的电脑修改
//MARK: - 打开数据库
//返回值:bool
let ret = tdb.open()
if ret{
print("数据库打开成功")
}
else{
print("数据库打开失败")
}
return tdb
}()
override func viewDidLoad() {
super.viewDidLoad()
//self.creatTable()
//插入单条数据
//self.insertData()
//插入多条数据
// for item in 0...100{
// let name = "name\(item)"
// let age = arc4random() % 15 + 15
// let sex = arc4random() % 2 == 0 ? "男" : "女"
// self.insertData(name, age: Int(age), sex: sex)
// }
//更新数据
//self.updateData()
//删除数据
//self.deleteData()
//获取数据
self.getData()
}
}
//MARK: - 数据库操作
extension ViewController{
//MARK: - 创建表
func creatTable(){
//1.创建新建表的sql语句
let sqlStr = "CREATE TABLE IF NOT EXISTS t_Person (id integer PRIMARY KEY AUTOINCREMENT,name text NOT NULL,age integer DEFAULT 20,sex text DEFAULT '女');"
//2.执行sql语句
//参数1:需要执行的sql语句
//参数2:sql语句中的占位符对应的值(下面代码有讲解)
//返回值:bool
let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
//3.判断执行结果
if ret {
print("sql语句执行成功")
}
else{
print("sql语句执行失败")
}
}
//MARK: - 插入单条数据
func insertData(){
//1.创建sql语句
let sqlStr = "INSERT INTO t_Person(name,sex,age) VALUES('小明','男',22);"
//2.执行sql语句
let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
//3.判断执行结果
if ret {
print("数据插入成功")
}
else{
print("数据插入失败")
}
}
//MARK: - 插入多条数据
func insertData(name:String,age:Int,sex:String){
//"?"是sql语句中的占位符,sql语句中不确定的值可以用"?"来代替,在执行sql语句的时候再给这个问号对应的值赋值
let sqlStr = "INSERT INTO t_Person(name,sex,age) VALUES(?,?,?);"
//2.执行sql语句
//参数1:需要执行的sql语句
//参数2:sql语句中的占位符对应的值
//返回值:bool
let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [name,sex,age])
//3.判断执行结果
if ret {
print("数据插入成功")
}
else{
print("数据插入失败")
}
}
//MARK: - 更新数据
func updateData(){
//1.创建sql语句
let sqlStr = "UPDATE t_Person SET age = 18 WHERE age < 18;"
//2.执行sql语句
let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
//3.判断执行结果
if ret {
print("数据更新成功")
}
else{
print("数据更新失败")
}
}
//MARK: - 删除数据
func deleteData(){
//1.创建sql语句
let sqlStr = "DELETE FROM t_Person WHERE age < 21 AND sex = '男';"
//2.执行sql语句
let ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [])
//3.判断执行结果
if ret {
print("数据删除成功")
}
else{
print("数据删除失败")
}
}
//数据查询
func getData(){
//1.创建sql语句
let sqlStr = "SELECT * FROM t_Person;"
//2.执行sql语句
//参数1:需要执行的sql语句
//参数2:sql语句中的占位符对应的值
//返回值:查询结果的集合
let dataSet = self.db.executeQuery(sqlStr, withArgumentsInArray: [])
//3.获取结果集合中的数据
while dataSet.next(){
//获取每个结果的内容
//字符串和二进制通过object方式获取
//参数:字段名字
let name = dataSet.objectForColumnName("name")
let sex = dataSet.objectForColumnName("sex")
//获取整型数据使用int开头的方法(获取浮点型数据使用double开头的方法)
let age = dataSet.intForColumn("age")
print(name,age,sex)
}
}
}
将网络请求与数据库结合使用
本例子实现的效果是将网络请求的数据通过数据库缓存到本地,StoryBoard启动页面已经改成MyViewController
- MyViewController
import UIKit
import Alamofire
import Kingfisher
class MyViewController: UITableViewController {
//MARK: - 属性
//1.数据源数组
lazy var dataArray:[DataModel] = {
return [DataModel]()
}()
//2.任务队列
lazy var queue:NSOperationQueue = {
let tqueue = NSOperationQueue()
//最大并发数
tqueue.maxConcurrentOperationCount = 3
return tqueue
}()
//3.数据库管理者
let manager = FMDBManager.defaultManager
//4.判断是否是第一次获取到的网络数据
var isFirstNetData = true
//MARK: - 生命周期
override func viewDidLoad() {
super.viewDidLoad()
//print(NSHomeDirectory())
//FMDBManager().creatTable() //测试
//测试创建数据库和表只执行了一次(测试此处时FMDBManager不是单例对象)
//let fm = FMDBManager()
//print(fm.db) //第一次会懒加载
//print(fm.db) //第二次不会在执行创建表
//测试
//let tdataArray = self.manager.getAllData()
//for item in tdataArray{
// print(item.title)
//}
//1.判断当前网络状态
if self.hasNetWork(){
//请求网络数据
print("请求网络数据")//测试
//网络请求成功之前用本地数据顶着
self.dataArray = self.manager.getAllData()
self.getNetData()
}
else{
//获取本地数据
print("使用本地数据")//测试
self.dataArray = self.manager.getAllData()
}
}
}
//MARK: - 判断网络状态
extension MyViewController{
func hasNetWork() -> Bool{
//拿到当前的网络状态
let status = Reachability.reachabilityForInternetConnection().currentReachabilityStatus()
//判断网络状态
if status == NotReachable{
return false
}
return true
}
}
//MARK: - 网络请求
extension MyViewController{
func getNetData(){
let urlStr = "http://0.0.0.0:[email protected]/api/articles/hot.json"
Alamofire.request(.GET, urlStr, parameters: ["pn":0,"size":15], encoding: ParameterEncoding.URL, headers: nil).responseJSON(options: .MutableContainers) { (data) in
//print(data)//测试
//判断数据是否为空
if let json = data.result.value{
//拿到数组
let articles = json.objectForKey("articles") as! [NSDictionary]
//在第一次网络请求成功后移除通过本地获取的数据
if self.isFirstNetData{
self.dataArray.removeAll()
self.isFirstNetData = false
}
//遍历数组
for dict in articles{
//根据字典创建数据模型
let model = DataModel(dict: dict)
//将数据存放到数据库中(异步最佳)
self.queue.addOperationWithBlock({
self.manager.insertData(model)
})
//将模型存到数组中
self.dataArray.append(model)
}
//刷新tableView !!!
self.tableView.reloadData()
}
else{
print("网络请求失败")
}
}
}
}
//MARK: - tabView协议方法
extension MyViewController{
//1.设置cell个数
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
//2.创建cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("cell")
if cell == nil{
cell = UITableViewCell(style: .Subtitle, reuseIdentifier: "cell")
}
//刷新数据
let model = self.dataArray[indexPath.row]
if model.img != nil{
cell?.imageView?.kf_setImageWithURL(NSURL(string: model.img!)!, placeholderImage: nil)
}
cell?.textLabel?.text = model.title
cell?.textLabel?.numberOfLines = 0
cell?.detailTextLabel?.text = model.feed_title + " " + model.time
cell?.selectionStyle = .None
return cell!
}
//3.设置cell高度
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 120
}
}
- 数据库管理对象FMDBManager
import UIKit
class FMDBManager: NSObject {
//MARK: - 属性
//1.单例
static let defaultManager = FMDBManager()
private override init() {
super.init()
}
//2.数据库
//懒加载保证数据库只创建一次和打开一次
lazy var db:FMDatabase = {
//1.创建数据库
//.db和.sqlite都是数据库文件后缀,随便选一个
let path = NSHomeDirectory() + "/Documents/user.db"
let tdb = FMDatabase(path: path)
//2.打开数据库
let ret = tdb.open()
//判断
if ret{
print("数据库打开成功")
}
else{
print("数据库打开失败")
}
//创建表
//在懒加载中创建表保证只执行一次
self.creatTable(tdb)
return tdb
}()
//MARK: - 方法
//MARK: - 创建表
func creatTable(tdb:FMDatabase){
let sqlStr = "CREATE TABLE IF NOT EXISTS t_DataModel(keyId integer PRIMARY KEY AUTOINCREMENT,feed_title text NOT NULL,id text NOT NULL UNIQUE,img text,time_t text NOT NULL,title text NOT NULL);"
//执行sql语句
let ret = tdb.executeUpdate(sqlStr, withArgumentsInArray: [])
//判断
if ret{
print("建表成功")
}
else{
print("建表失败")
}
}
//MARK: - 将数据插入到数据库
func insertData(model:DataModel){
//创建sql语句
let sqlStr = "INSERT INTO t_DataModel(feed_title,id,img,time_t,title) VALUES(?,?,?,?,?);"
//执行结果
var ret:Bool = false
//执行sql语句
if model.img == nil{
ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [model.feed_title,model.id,"",model.time,model.title])
}
else{
ret = self.db.executeUpdate(sqlStr, withArgumentsInArray: [model.feed_title,model.id,model.img!,model.time,model.title])
}
//判断
if ret{
print("数据插入成功")
}
else{
print("数据插入失败")
}
}
//MARK: - 获取指定数据
func getData(page:Int,size:Int){
//方案1:
//获取到整张表的数据个数,算出约束的第一个值
//方案2:
//全部查询出来,逆序
//let sqlStr = "SELECT * FROM t_DataModel LIMIT 0,20;"
}
//MARK: - 获取所有数据
func getAllData() -> [DataModel]{
var tempArray = [DataModel]()
//创建查询语句
let sqlStr = "SELECT * FROM t_DataModel;"
//执行sql语句
let dataSet = self.db.executeQuery(sqlStr, withArgumentsInArray: [])
//遍历结果集合获取数据
while dataSet.next(){
//创建数据模型用来获取数据
let model = DataModel()
model.feed_title = dataSet.objectForColumnName("feed_title") as! String
model.id = dataSet.objectForColumnName("id") as! String
model.img = dataSet.objectForColumnName("img") as? String
model.time = dataSet.objectForColumnName("time_t") as! String
model.title = dataSet.objectForColumnName("title") as! String
//存储数据
tempArray.append(model)
}
return tempArray
}
}
- 数据模型DataModel
import UIKit
class DataModel: NSObject {
//属性
var feed_title = ""
var id = ""
var img:String? = nil
var time = ""
var title = ""
//方法
init(dict:NSDictionary) {
self.feed_title = dict["feed_title"] as! String
self.id = dict["id"] as! String
self.img = dict["img"] as? String
self.time = dict["time"] as! String
self.title = dict["title"] as! String
}
override init() {
super.init()
}
}