swift 2 时代的 coredata 增删改查

写这个是对coredata这个内置的数据库的一个总结

默认读者已经对 coredata 有了基本了解,并未涉及 relationships 等高级功能,只是对coredata的各类基本操作做个总结

通过这些简单的命令,可以让您很快做好一个数据库的操作,轻松构建 todo 或记事本等需要操作本地数据库的 app

一,准备工作
1,创建项目的时候,勾选“**Use Core Data
**”。完毕后在 **AppDelegate
** 中,会生成相关代码。

如果想在已有的项目中新集成 coredata 请参考这里

2,打开项目中的 xcdatamodeld 文件,在右边的数据模型编辑器的底部工具栏点击 Add Entity 添加实体。
同时在属性栏中对实体命名进行修改,并在 **Attribute
** 栏目中添加 **userID
userName
userImage
** 三个属性用以存储客户基本资料。

Paste_Image.png

3,还要为每一个实体生成一个对应的 **NSManagedObject
** 子类,通过类的成员属性来访问和获取数据。
新建选择 **Core Data
** 项下面 **NSManagedObject subclass
** 类型文件,生成该实体同名的类。

Paste_Image.png

这一步不做也可以,不做就是用kvc的方式访问,但做了可以用访问器下标的方式访问

真正用起来方便很多,不容易出错外,访问器的效率还比kvc高那么点,建议生成该类

当然这中间有个坑,放在最后说

4,下面就是很正常的勾选和选择存放地点

Paste_Image.png

语言 swift


Paste_Image.png

二,Core Data的使用

开始代码之前先了解几个概念

(1)NSManagedObjectModel(被管理的对象模型) 相当于实体,不过它包含 了实体间的关系

(2)NSManagedObjectContext(被管理的对象上下文) 操作实际内容
作用:插入数据 查询 更新 删除

(3)NSPersistentStoreCoordinator(持久化存储助理) 相当于数据库的连接器

(4)NSFetchRequest(获取数据的请求) 相当于查询语句

(5)NSPredicate(相当于查询条件)

(6)NSEntityDescription(实体结构)

(7)后缀名为.xcdatamodel的包 里面的.xcdatamodel文件,用数据模型编辑器编辑

编译后为.momd或.mom文件,这就是为什么文件中没有这个东西,而我们的程序中用到这个东西而不会报错的原因

了解后我们可以开始码田了

1,首先在代码中引入CoreData库###

import CoreData

2,为了方便访问,把同样的东西先放进class###

class CoreDataFunc: NSObject {

    //1 在我们想要保存或者获取任何数据之前我们必须获取NSManagedObjectContext,理解为暂存器
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext

    //2 entity的名字
    let entityName:String = "UserData"

    //3 系统想要的读取数据的entity
    var fetchRequest : NSFetchRequest{ return NSFetchRequest(entityName:entityName) }
}

3,保存数据###

用法:data 传 ["ID", "名字", "头像"]

    func saveCoreData(data:[String]){     
   
        //为每一个实体生成一个对应的 NSManagedObject 子类,通过类的成员属性来访问和获取数据。新建选择 Core Data 项下面 NSManagedObject subclass 类型文件,生成该实体同名的类
        let user = NSEntityDescription.insertNewObjectForEntityForName(entityName, inManagedObjectContext: managedContext) as! UserData
        //然后就可以用下标方式赋值
        user.userID = data[0]
        user.userName = data[1]
        user.userImage = data[2]

        // 把‘暂存器’中的东西存到磁盘中
        do{
            try managedContext.save()
            print("save success")
        }catch{
            print("Could not save!")
        }
    }//func saveCoreData(){

如果上面没有生成 subclass ,那存储的方式就得将 do 之前的内容变成如下内容

        let entity = NSEntityDescription.entityForName(entityName, inManagedObjectContext:            managedContext)
        let user = NSManagedObject(entity: entity!, insertIntoManagedObjectContext:managedContext)

        user.setValue(data[0], forKey: "userID")
        user.setValue(data[1], forKey: "userName")
        user.setValue(data[2], forKey: "userImage")

4,获取所有数据###

key 参数为 attribute 的值,

返回类型可以随便选,这里初定为只返回名字,当然也可以返回所有数据

    func loadCoreData(key key:String = "userName") -> [String]{

        var result : [String] = []
        do{
            let fetchedResults = try managedContext.executeFetchRequest(fetchRequest) 
            for each in fetchedResults{

                let name:String = each.valueForKey(key) as! String
                result.append(name)
            }
            print("read success")
        }catch{
            print("load Data from coreData error")
        }
        return result
    }//loadCoreData

5,查询记录###

用法:条件输入查询条件 condition = "userID= '1' "
条件 condition 为nil的时候则返回所有资料,和 loadCoreData 功能相同

    func searchCoreData(condition:String?) -> [UserData]?{

        //必须使用新 fetch
        let fetchRequest:NSFetchRequest = NSFetchRequest()
        fetchRequest.fetchLimit = 10 //限定查询结果的数量
        fetchRequest.fetchOffset = 0 //查询的偏移量

        //设置数据请求的实体结构
        fetchRequest.entity = NSEntityDescription.entityForName("UserData", inManagedObjectContext: managedContext)

        //设置查询条件,条件为nil的时候则返回所有资料
        if let _ = condition {
            fetchRequest.predicate = NSPredicate(format: condition!, "")
        }

        //查询操作
        do {
            let fetchedObjects:[AnyObject]? = try managedContext.executeFetchRequest(fetchRequest)

            guard fetchedObjects?.count > 0 else { return nil}
            return fetchedObjects as? [UserData]
            
        }
        catch {
            fatalError("could not search:\(error)")
        }
    }
这里可以使用的条件很丰富,相当于 where 在数据库中的用法

where userID == 1的情况,用于查询

"userID= '1' "

主要牵扯到 NSPredicate 的用法

NSPredicate(format: "userName= 'dafadsf' ", "")
userName == dafadsf 的情况

>NSPredicate(format: "SELF MATCHES %@", "^[A-Za-z].+") //判断字符串首字母是否为字母

Format:
(1)比较运算符>,<,==,>=,<=,!=
可用于数值及字符串
例:@"number > 100"

(2)范围运算符:IN、BETWEEN
例:"number BETWEEN {1,5}"
"address IN {'shanghai','beijing'}"

(3)字符串本身:SELF
例:"SELF == 'APPLE'"

(4)字符串相关:BEGINSWITH、ENDSWITH、CONTAINS
例:"name CONTAINS[cd] 'ang'" //包含某个字符串
"name BEGINSWITH[c] 'sh'" //以某个字符串开头
"name ENDSWITH[d] 'ang'" //以某个字符串结束
注:[c]不区分大小写[d]不区分发音符号即没有重音符号[cd]既不区分大小写,也不区分发音符号。

(5)通配符:LIKE
例:"name LIKE[cd] 'er'" // * 代表通配符,Like也接受[cd].
"name LIKE[cd] '???er*'"

(6)正则表达式:MATCHES
例:let regex = "^A.+e$"; //以A开头,e结尾
"name MATCHES %@",regex

基本可以应付常见情况了

6,删除单条数据

condition 同上的条件用法

    func delCoreData(condition : String){
        
        //设置查询条件
        fetchRequest.predicate = NSPredicate(format: condition, "")

        //查询操作
        do {

            let fetchedObjects:[AnyObject]? = try managedContext.executeFetchRequest(fetchRequest)
            guard fetchedObjects?.count > 0 else { print("not found in coredata"); return }
            
            managedContext.deleteObject(fetchedObjects![0] as! NSManagedObject)
            try managedContext.save()
            print("del success")

        }catch{
            print("CoreData delete data fail")
        }
    }//func delCoreData

7,删除所有数据###

该条多用于退出app时删除所有记录

不过不知道出于什么原因,苹果在 ios9 之前都没有相关的方法提供可以一次性的删除所有数据

最常见的做法是用删单条的方法建立 for 循环一个一个删,这样的后果就是效率很低

所以最快的方法就是把生成的 sqlite 数据文件整个删除,swift 2 中删除方法如下

 func removeCoreData(){

    guard let psc = managedContext.persistentStoreCoordinator else { return }
    guard let store = psc.persistentStores.last as NSPersistentStore? else { return }
    let storeUrl = psc.URLForPersistentStore(store)
                
                managedContext.performBlockAndWait() {
                    
                    self.managedContext.reset()
                    
                    do{
                        try psc.removePersistentStore(store)
                        try NSFileManager.defaultManager().removeItemAtURL(storeUrl)
                        try psc.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: storeUrl, options: nil)
                        print("remove coredata file success!")

                    }catch{
                        print("remove coredata file error")
                    }
                    
                }//managedContext.performBlockAndWait()
        
    }//func removeCoreData()

ios 9 以后出来的方法


        if #available(iOS 9.0, *) {
            let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

            // delegate objects
            let myManagedObjectContext = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
            let myPersistentStoreCoordinator = (UIApplication.sharedApplication().delegate as! AppDelegate).persistentStoreCoordinator

            // perform the delete
            do {

                try myPersistentStoreCoordinator.executeRequest(deleteRequest, withContext: myManagedObjectContext)

            } catch let error as NSError {

                print(error)

            }
            return
        }//if #available(iOS 9.0, *)

ok,可以这样调用

删除整个数据库内容

CoreDataFunc().removeCoreData()

Paste_Image.png

删除 userName 等于 12331 的记录

CoreDataFunc().delCoreData("userName= '12331'")

Paste_Image.png

显示所有记录

func show(){
guard let d = CoreDataFunc().searchCoreData(nil) else { print("no data in coredata"); return }
for i in d {
print(i.userID, i.userName, i.userImage)
}
}

Paste_Image.png

保存一条信息

let data = [ "12", "12adsfasdfasdf", "baidu"]
CoreDataFunc().saveCoreData(data)

Paste_Image.png
中间建立 subclass 有个坑######

某些特殊的情况下,建立 subclass 存储的时候会发现无法存储的情况,这时候要在 这个subclass 文件前加上
@objc(className)
例:

@objc(UserData)
class UserData: NSManagedObject {

// Insert code here to add functionality to your managed object subclass

}

以上

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容