技术标签: Realm.swift (一) 使用篇 IOS数据存储
Realm 是一个跨平台的移动数据库引擎,其性能要优于 Core Data 和 FMDB - 移动端数据库性能比较, 我们可以在 Android 端 realm-java,iOS端:Realm-Cocoa,同时支持 OC 和 Swift两种语言开发。其使用简单,免费,性能优异,跨平台的特点广受程序员GG喜爱。
如下表是在代码中声明的实例:
类型 | 非可选值形式 | 可选值形式 |
---|---|---|
Bool | dynamic var value = false | let value = RealmOptional() |
Int | dynamic var value = 0 | let value = RealmOptional() |
Float | dynamic var value: Float = 0.0 | let value = RealmOptional() |
Double | dynamic var value: Double = 0.0 | let value = RealmOptional() |
String | dynamic var value = “” | dynamic var value: String? = nil |
Data | dynamic var value = NSData() | dynamic var value: NSData? = nil |
Date | dynamic var value = NSDate() | dynamic var value: NSDate? = nil |
Object | 必须是可选值 | dynamic var value: Class? |
List | let value = List() | 必须是非可选值 |
LinkingObjects | let value = LinkingObjects(fromType: Class.self, property: “property”) | 必须是非可选值 |
pod 'RealmSwift'
pod 'Realm'
/// 配置数据库
public class func configRealm() {
/// 如果要存储的数据模型属性发生变化,需要配置当前版本号比之前大
let dbVersion : UInt64 = 2
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/defaultDB.realm")
let config = Realm.Configuration(fileURL: URL.init(string: dbPath), inMemoryIdentifier: nil, syncConfiguration: nil, encryptionKey: nil, readOnly: false, schemaVersion: dbVersion, migrationBlock: {
(migration, oldSchemaVersion) in
}, deleteRealmIfMigrationNeeded: false, shouldCompactOnLaunch: nil, objectTypes: nil)
Realm.Configuration.defaultConfiguration = config
Realm.asyncOpen {
(realm, error) in
if let _ = realm {
print("Realm 服务器配置成功!")
}else if let error = error {
print("Realm 数据库配置失败:\(error.localizedDescription)")
}
}
}
import UIKit
import RealmSwift
class Book: Object {
@objc dynamic var name = ""
@objc dynamic var author = ""
/// LinkingObjects 反向表示该对象的拥有者
let owners = LinkingObjects(fromType: Student.self, property: "books")
}
class Student: Object {
@objc dynamic var name = ""
@objc dynamic var age = 18
@objc dynamic var weight = 156
@objc dynamic var id = 0
@objc dynamic var address = ""
@objc dynamic var birthday : NSDate? = nil
@objc dynamic var photo : NSData? = nil
//重写 Object.primaryKey() 可以设置模型的主键。
//声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。
//一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
override static func primaryKey() -> String? {
return "id"
}
//重写 Object.ignoredProperties() 可以防止 Realm 存储数据模型的某个属性
override static func ignoredProperties() -> [String] {
return ["tempID"]
}
//重写 Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引,Realm 支持为字符串、整型、布尔值以及 Date 属性建立索引。
override static func indexedProperties() -> [String] {
return ["name"]
}
//List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
let books = List<Book>()
}
Object
类的子类。重写 Object.primaryKey() 可以设置模型的主键。
声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。
一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
override static func primaryKey() -> String? {
return "id"
}
重写 Object.ignoredProperties() 可以防止 Realm 存储数据模型的某个属性。Realm 将不会干涉这些属性的常规操作,它们将由成员变量(var)提供支持,并且您能够轻易重写它们的 setter 和 getter。
override static func ignoredProperties() -> [String] {
return ["tempID"]
}
重写 Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引,Realm 支持为字符串、整型、布尔值以及 Date 属性建立索引。
override static func indexedProperties() -> [String] {
return ["name"]
}
List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
List 中可以包含简单类型的 Object,表面上和可变的 Array 非常类似,所用的方法和访问数据的方式(索引和下标)都相同,并且所包含的所有对象都应该是相同类型的。声明前面不可加 dynamic ,因为在 Objective-C 运行时无法表示泛型属性。
注意:List 只能够包含 Object 类型,不能包含诸如String之类的基础类型。
//List 用来表示一对多的关系:一个 Student 中拥有多个 Book。
let books = List<Book>()
通过反向关系(也被称为反向链接(backlink)),您可以通过一个特定的属性获取和给定对象有关系的所有对象。 Realm 提供了“链接对象 (linking objects)” 属性来表示这些反向关系。借助链接对象属性,您可以通过指定的属性来获取所有链接到指定对象的对象。
例如:一个 Book 对象可以拥有一个名为 owners 的链接对象属性,这个属性中包含了某些 Student 对象,而这些 Student 对象在其 books 属性中包含了这一个确定的 Book 对象。您可以将 owners 属性设置为 LinkingObjects 类型,然后指定其关系,说明其当中包含了其拥有者 Student 对象。
let owners = LinkingObjects(fromType: Student.self, property: "books")
import UIKit
import RealmSwift
class XWStudentRealmTool: Object {
private class func getDB() -> Realm {
let docPath = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0] as String
let dbPath = docPath.appending("/defaultDB.realm")
/// 传入路径会自动创建数据库
let defaultRealm = try! Realm(fileURL: URL.init(string: dbPath)!)
return defaultRealm
}
}
/// 增
extension XWStudentRealmTool {
public class func insertStudent(by student : Student) -> Void {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(student)
}
print(defaultRealm.configuration.fileURL ?? "")
}
}
func testInsterStudent() {
let stu = Student()
stu.name = "极客学伟"
stu.age = 26
stu.id = 2;
let birthdayStr = "1993-06-10"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"
stu.birthday = dateFormatter.date(from: birthdayStr)! as NSDate
stu.weight = 160
stu.address = "回龙观"
XWStudentRealmTool.insertStudent(by: stu)
}
通过 Realm Browser 查看刚才保存的数据
通过 print(realm.configuration.fileURL ?? "")
打印数据路径
效果:
//测试在数据库中插入一个拥有多本书并且有头像的学生对象
func testInsertStudentWithPhotoBook() {
let stu = Student()
stu.name = "极客学伟_有头像_有书"
stu.weight = 151;
stu.age = 26
stu.id = 3;
// 头像
stu.setPhotoWitName("cat")
let bookFubaba = Book.init(name: "富爸爸穷爸爸", author: "[美]罗伯特.T.清崎")
let bookShengmingbuxi = Book.init(name: "生命不息, 折腾不止", author: "罗永浩")
let bookDianfuzhe = Book(value: ["颠覆着: 周鸿祎自传","周鸿祎"])
stu.books.append(bookFubaba);
stu.books.append(bookShengmingbuxi);
stu.books.append(bookDianfuzhe);
XWStudentRealmTool.insertStudent(by: stu)
}
运行结果:
会自动创建数据库并新建两个表 Student 和 Book, 并将两者进行关联
保存方法
/// 保存一些Student
public class func insertStudents(by students : [Student]) -> Void {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(students)
}
print(defaultRealm.configuration.fileURL ?? "")
}
//测试在数据库中插入多个拥有多本书并且有头像的学生对象
func testInsertManyStudent() {
var stus = [Student]()
for i in 100...144 {
let stu = Student()
stu.name = "极客学伟_\(i)"
stu.weight = 151;
stu.age = 26
stu.id = i;
// 头像
stu.setPhotoWitName("cat")
let birthdayStr = "1993-06-10"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd"
stu.birthday = dateFormatter.date(from: birthdayStr)! as NSDate
stus.append(stu)
}
XWStudentRealmTool.insertStudents(by: stus)
}
演示结果:
/// 获取 所保存的 Student
public class func getStudents() -> Results<Student> {
let defaultRealm = self.getDB()
return defaultRealm.objects(Student.self)
}
let stus = XWStudentRealmTool.getStudents()
for stu in stus {
print(stu.name)
if stu.photo != nil {
self.imageV.image = stu.getPhotoImage()
}
if stu.books.count > 0 {
for book in stu.books {
print(book.name + "+" + book.author)
}
}
}
演示结果:
将获取的头像为imageView赋值
/// 获取 指定id (主键) 的 Student
public class func getStudent(from id : Int) -> Student? {
let defaultRealm = self.getDB()
return defaultRealm.object(ofType: Student.self, forPrimaryKey: id)
}
// 通过主键查询
func testSearchStudentByID(){
let student = XWStudentRealmTool.getStudent(from: 110)
if let studentL = student {
print(studentL.name)
}
}
演示结果:
对应数据库中:
/// 获取 指定条件 的 Student
public class func getStudentByTerm(_ term: String) -> Results<Student> {
let defaultRealm = self.getDB()
print(defaultRealm.configuration.fileURL ?? "")
let predicate = NSPredicate(format: term)
let results = defaultRealm.objects(Student.self)
return results.filter(predicate)
}
// 条件查询
func testSearchTermStudent() {
let students = XWStudentRealmTool.getStudentByTerm("name = '极客学伟_110'")
if students.count == 0 {
print("未查询到任何数据")
return
}
for student in students {
print(student.name,student.weight)
}
}
输出结果:
// 根据名字升序查询
let stus = realm.objects(Student.self).sorted(byKeyPath: "id")
// 根据名字降序序查询
let stus = realm.objects(Student.self).sorted(byKeyPath: "id", ascending: false)
/// 更新单个 Student
public class func updateStudent(student : Student) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(student, update: true)
}
}
/// 更新多个 Student
public class func updateStudent(students : [Student]) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.add(students, update: true)
}
}
测试代码
/// 批量更改
func testUpdateStudents() {
var stus = [Student]()
for i in 100...144 {
let stu = Student()
stu.name = "极客学伟改名_\(i)"
stu.weight = 148;
stu.age = 27
stu.id = i;
stus.append(stu)
}
XWStudentRealmTool.updateStudent(students: stus)
}
更新之前:
更新之后:
/// 更新多个 Student
public class func updateStudentAge(age : Int) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
let students = defaultRealm.objects(Student.self)
students.setValue(age, forKey: "age")
}
}
测试代码:
/// 批量更改年龄
func testUpdateStudentsAge() {
XWStudentRealmTool.updateStudentAge(age: 18)
}
演示结果:
/// 删除单个 Student
public class func deleteStudent(student : Student) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.delete(student)
}
}
/// 删除多个 Student
public class func deleteStudent(students : Results<Student>) {
let defaultRealm = self.getDB()
try! defaultRealm.write {
defaultRealm.delete(students)
}
}
测试代码:
/// 删除id 为 3 的学生
func testDeleteOneStudent() {
let stu = XWStudentRealmTool.getStudent(from: 3)
if stu != nil {
XWStudentRealmTool.deleteStudent(student: stu!)
}
}
/// 删除所有
func testDeleteAllStudent() {
let stus = XWStudentRealmTool.getStudents()
XWStudentRealmTool.deleteStudent(students: stus)
}
删除后的数据库:
<br />查询的时候出现这个问题可能又两种可能,<br />1.实体类和对应的xml文件不一致,这个要查看数据库中的字段是否有缺少,最主要的就是有外键关系的,是否把多对一和一对多的关系全部对应上了。另外就是多对一的时候如: <br /> <many-to-one name="staffAdmin" class="com.beauty.entity.StaffAdmin" fetch="select" lazy="false"><br /> <column name="staf
先来了解什么叫做抽象父类有个计算面积的方法,但是不同的图形计算面积的方式是不一样的。所以这里的计算面积的方法就是个抽象的方法。只有到具体的子类里面才能去实现具体的计算面积的方法动物类是父类。有吃东西的方法。但是具体吃什么要看子类如狗吃的是骨头。猫吃的是鱼。动物这个类是个抽象的概念不够具体转载于:https://www.cnblogs.com/wangjun...
1、帮助文档svdSingular value decompositionSyntaxs = svd(X)[U,S,V] = svd(X)[U,S,V] = svd(X,0)[U,S,V] = svd(X,'econ')DescriptionThe svd command computes the matrix singularvalue dec
磁性材料主要包含永磁材料和软磁材料两大类,以矫顽力进行区分,通常将矫顽力低于10kA/m的材料称为软磁材料(也有将矫顽力在1kA/m---10kA/m的材料称为半硬半软材料),根据材料的矫顽力大小,在测量方面选择不同的测试方法进行。一、软磁材料直流磁特性测量:参考标准:GB/T13012、IEC60404-4对于矫顽力小于1kA/m的软磁材料材料,主要包含:电工纯铁、电工硅钢...
Linux是一套免费使用和自由传播的类Unix操作系统(主要用在服务器上),是一个基于POSIX和UNIX的多用户、多任务、支持多线程和多CPU的操作系统。目前市面上较知名的发行版有:Ubuntu、RedHat、CentOS、Debian、Fedora、SuSE、OpenSUSE、Arch Linux、SolusOS 等。Linux 操作系统架构。...
哪吒人生信条:如果你所学的东西 处于喜欢 才会有强大的动力支撑。把你的前端拿捏得死死的,每天学习得爽爽的,如果你所学的东西 处于喜欢 才会有强大的动力支撑。感谢不负每一份热爱前端的程序员,不论前端技能有多奇葩,欢迎关注加我入群vx:xiaoda0423前言希望可以通过这篇文章,能够给你得到帮助。(感谢一键三连)1.HTML5表单增加的输入类型url类型:专门为输入url地址定义的文本库,在验证输入文本的格式时,如果文本框中的的内容不符合url地址的格式,会提示验证错误。email类型:
1. 当前系统日期、时间 select getdate()2. dateadd 在向指定日期加上一段时间的基础上,返回新的 datetime 值 例如:向日期加上2天 select dateadd(day,2,'2004-10-15') --返回:2004-10-17 00:00:00.0003. datediff 返回跨两个指定日期的...
假如现在创建了一个package的文件夹,在package文件中有三个文件,__init__.py,pk1.py,pk2.py其中__init__.py为空文件pk1.py文件内容为:def pk1(): return 1pk2.py文件内容为:from .pk1 import *def pk2(): return pk1() + 1所以可以...
JS是一门轻量级的语言,不支持高级语言的继承语法,但是可以通过call或apply函数(这两个函数实现结果一样,用法略有不同,本文主要讲解call函数的使用方法)实现继承的效果,下面举个例子来讲解。一、call函数的使用方法// 基类var father = function() { this.say = function() { alert('父亲'); }}// 子类v
这是一个老掉牙的问题了,现在写,一是因为我才接触这一类界面美化(以前一直以功能为主,需要漂亮界面也都是自己画的),二是发现网上的内容很多不准确,所以在这里整理一下。1,Manifest方法(下面其它方法也都是以此为基础的) 用文本编辑器编写一个App.exe.Manifest文件,放到App.exe同文件夹下,注意与App同名。 <?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xm...
Win10+Ubuntu双系统安装配置教程(二)——磁盘分区
1、主干开发在这种模式下,开发人员几乎总是签入代码到主干,而使用分支的情况极少。主干开发有如下三个好处:确保所有的代码被持续集成 确保开发人员及时获得他人的修改 避免项目后期的“合并地狱”和“集成地狱”缺点:每次向主干签入并不都是可发布状态2、按发布创建分支在这种模式下,在某个版本即将发布之前,创建一个分支,该发布版本的测试和验证全部在该分支上进行,而最新的开发工作仍旧在主干上进行。要遵循如下规则:一直在主干上开发新功能 当待发布版本的所有功能都完成了,且希望继续开发新功能时