Swift - Realm数据库的使用详解(附样例)

使用Realm Swift进行iOS应用开发 通过Realm Swift,我们可以轻松地处理本地数据存储和访问,以及执行各种数据操作。如果在应用程序的后续版本中更改了数据模型,我们需要执行数据库迁移。Realm Swift提供了一个简单的迁移机制,可以帮助我们进行平滑的数据模型更新。首先,我们需要将Realm Swift添加到我们的项目中。在使用Realm Swift之前,我们需要定义数据模型。在迁移块中,我们可以编写逻辑来处理旧模式版本和执行必要的数据迁移操作。使用Realm Swift,我们可以执行多种数据操作,包括创建、读取、更新和删除对象。 阅读详情

1,什么是Realm
Realm  于2014 年7月发布,是一个跨平台的移动数据库引擎,专门为移动应用的数据持久化而生。其目的是要取代   Core Data  和   SQLite。

2,关于Realm,你要知道下面几点:
(1)使用简单,大部分常用的功能(比如插入、查询等)都可以用一行简单的代码轻松完成,学习成本低。
(2) Realm  不是基于   Core Data,也不是基于   SQLite  封装构建的。它有自己的数据库存储引擎。
(3) Realm  具有良好的跨平台特性,可以在   iOS  和   Android  平台上共同使用。代码可以使用   Swift  、   Objective-C 以及   Java 语言来编写。
(4) Realm  还提供了一个轻量级的数据库查看工具( Realm Browser)。你也可以用它进行一些简单的编辑操作(比如插入和删除操作)  

3,支持的类型
(1) Realm  支持以下的属性类型: Bool、 Int8、 Int16、 Int32、 Int64、 Double、 Float、 String、 Date(精度到秒)以及 Data.
(2)也可以使用   List<object> 和   Object  来建立诸如一对多、一对一之类的关系模型,此外   Object  的子类也支持此功能。

4,Realm的安装配置 
(1)先去   Realm  的官网去下载最新框架: http://static.realm.io/downloads/swift/latest。(或者使用cocoapods下载RealmSwift第三方。最新的使用方法案例官网地址: https://realm.io/cn/docs/swift/latest/)
(2)拖拽   RealmSwift.framework 和   Realm.framework 文件到” Embedded Binaries”选项中。选中   Copy items if needed 并点击   Finish
原文:Swift - Realm数据库的使用详解(附样例)


5,将数据插入到数据库中
下面代码判断默认数据库中是否有数据,如果没有的话将几个自定义对像插入到数据库中。
(1)这里以个人消费记录为例,我们先定义消费类别类,和具体消费记录类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import   Foundation
import   RealmSwift
 
//消费类型
class   ConsumeType : Object   {
     //类型名
     @objc   dynamic   var   name =  ""
}
 
//消费条目
class   ConsumeItem : Object   {
     //条目名
     @objc   dynamic   var   name =  ""
     //金额
     @objc   dynamic   var   cost = 0.00
     //时间
     @objc   dynamic   var   date =  Date ()
     //所属消费类别
     @objc   dynamic   var   type: ConsumeType ?
}

(2)判断数据库记录是否为空,空的话则插入数据库(这里以默认数据库为例)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import   UIKit
import   RealmSwift
 
class   ViewController :  UIViewController   {
     
     override   func   viewDidLoad() {
         super .viewDidLoad()
         
         //使用默认的数据库
         let   realm = try!  Realm ()
         //查询所有的消费记录
         let   items = realm.objects( ConsumeItem . self )
         //已经有记录的话就不插入了
         if   items.count>0 {
             return
         }
         
         //创建两个消费类型
         let   type1 =  ConsumeType ()
         type1.name =  "购物"
         let   type2 =  ConsumeType ()
         type2.name =  "娱乐"
         
         //创建三个消费记录
         let   item1 =  ConsumeItem (value: [ "买一台电脑" ,5999.00, Date (),type1])  //可使用数组创建
         
         let   item2 =  ConsumeItem ()
         item2.name =  "看一场电影"
         item2.cost = 30.00
         item2.date =  Date (timeIntervalSinceNow: -36000)
         item2.type = type2
         
         let   item3 =  ConsumeItem ()
         item3.name =  "买一包泡面"
         item3.cost = 2.50
         item3.date =  Date (timeIntervalSinceNow: -72000)
         item3.type = type1
         
         // 数据持久化操作(类型记录也会自动添加的)
         try! realm.write {
             realm.add(item1)
             realm.add(item2)
             realm.add(item3)
         }
         
         //打印出数据库地址
         print (realm.configuration.fileURL ??  "" )
     }
     
     override   func   didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
}

6,Data类型数据的存取
参考另一篇文章: Swift - Realm数据库中图片的插入、读取(Data类型数据的存储) 

7,使用Realm Browser查看数据库  
(1)默认数据库是应用的   Documents  文件夹下的一个名为“ default.realm”。
1
2
//打印出数据库地址
print (realm.configuration.fileURL ??  "" )
(2)使用   Realm Browser 工具可以很方便的对.realm数据库进行读取和编辑(在  App Store 中搜索  Realm Browser 即可下载)。
可以看到,上面的几个对象已经成功的插入到数据库中来。

原文:Swift - Realm数据库的使用详解(附样例)


原文:Swift - Realm数据库的使用详解(附样例)


8,从数据库中读取记录并显示到表格中来
(1)通过查询操作, Realm  将会返回包含   Object  集合的   Results  实例。 Results  的表现和   Array  十分相似,并且包含在   Results  中的对象能够通过索引下标进行访问。 
(2)所有的查询(包括查询和属性访问)在   Realm  中都是延迟加载的,只有当属性被访问时,才能够读取相应的数据。 
(3)查询结果并不是数据的拷贝:修改查询结果(在写入事务中)会直接修改硬盘上的数据。

下面我们把库里的数据加载出来,并通过表格显示出来。
效果图如下:
原文:Swift - Realm数据库的使用详解(附样例)


代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import   UIKit
import   RealmSwift
 
class   ViewController :  UIViewController ,  UITableViewDelegate ,  UITableViewDataSource    {
     
     @IBOutlet   weak   var   tableView:  UITableView !
     
     var   dformatter =  DateFormatter ()
     
     //保存从数据库中查询出来的结果集
     var   consumeItems: Results < ConsumeItem >?
     
     override   func   viewDidLoad() {
         super .viewDidLoad()
         
         self .dformatter.dateFormat =  "MM月dd日 HH:mm"
         
         self .tableView!.delegate =  self
         self .tableView!.dataSource =  self
         //创建一个重用的单元格
         self .tableView!.register( UITableViewCell . self , forCellReuseIdentifier:  "MyCell" )
         
         //使用默认的数据库
         let   realm = try!  Realm ()
         //查询所有的消费记录
         consumeItems = realm.objects( ConsumeItem . self )
     }
     
     //在本例中,只有一个分区
     func   numberOfSections( in   tableView:  UITableView ) ->  Int   {
         return   1;
     }
     
     //返回表格行数(也就是返回控件数)
     func   tableView(_ tableView:  UITableView , numberOfRowsInSection section:  Int ) ->  Int   {
         return   self .consumeItems!.count
     }
     
     //创建各单元显示内容(创建参数indexPath指定的单元)
     func   tableView(_ tableView:  UITableView , cellForRowAt indexPath:  IndexPath )
         ->  UITableViewCell   {
         //同一形式的单元格重复使用,在声明时已注册
         let   cell =  UITableViewCell (style: .value1, reuseIdentifier:  "MyCell" )
         let   item =  self .consumeItems![indexPath.row]
         cell.textLabel?.text = item.name +  " ¥"   +  String (format:  "%.1f" , item.cost)
         cell.detailTextLabel?.text =  self .dformatter.string(from: item.date)
         return   cell
     }
     
     override   func   didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
}

9,查询前N条数据
Realm无法直接限制查询数量。所以我们如果想要查出部分数据(比如前5条记录),也是全部查出来后在结果集中捞取。
1
2
3
4
5
6
//查询并取出前5条数据
let   dogs = try!  Realm ().objects( Dog . self )
for   i  in   0..<5 {
     let   dog = dogs[i]
     // ...
}
Realm为何无法限制查询数量?
通常查询数据库数据时,我们可以在sql语句中添加一些限制语句(比如 rownum, limit, top等)来限制返回的结果集的行数。
但我们使用Realm会发现,它没有这种分页功能,感觉不管查什么都是把所有的结果都捞出来。比如我们只要User表的前10条数据,那么做法是先查询出所有的User数据,再从结果集中取出前10条数据。
有人可能会担心,如果数据库中数据非常多,那每次都这么查不会影响性能吗?
其实大可放心,由于Realm都是延迟加载的,只有当属性被访问时,才能够读取相应的数据。不像通常数据库,查询后,查询结果是从数据库拷贝一份出来放在内存中的。而Realm的查询结果应该说是数据库数据的引用,就算你查出来,如果不用也不会占用什么内存。

10,支持断言查询(Predicate),这样可以通过条件查询特定数据
同时可以使用链式查询数据。
1
2
3
4
5
6
7
8
9
//查询花费超过10元的消费记录(使用断言字符串查询)
consumeItems = realm.objects( ConsumeItem . self ). filter ( "cost > 10" )
 
//查询花费超过10元的购物记录(使用 NSPredicate 查询)
let   predicate =  NSPredicate (format:  "type.name = '购物' AND cost > 10" )
consumeItems = realm.objects( ConsumeItem . self ). filter (predicate)
 
//使用链式查询
consumeItems = realm.objects( ConsumeItem . self ). filter ( "cost > 10" ). filter ( "type.name = '购物'" )
支持的断言:
  • 比较操作数(comparison operand)可以是属性名称或者某个常量,但至少有一个操作数必须是属性名称;
  • 比较操作符 ==、<=、<、>=、>、!=, 以及 BETWEEN 支持 int、long、long long、float、double 以及 NSDate 属性类型的比较,比如说 age == 45;
  • 相等比较 ==以及!=,比如说Results<Employee>().filter("company == %@", company)
  • 比较操作符 == and != 支持布尔属性;
  • 对于 NSString 和 NSData 属性来说,我们支持 ==、!=、BEGINSWITH、CONTAINS 以及 ENDSWITH 操作符,比如说 name CONTAINS ‘Ja’;
  • 字符串支持忽略大小写的比较方式,比如说 name CONTAINS[c] ‘Ja’ ,注意到其中字符的大小写将被忽略;
  • Realm 支持以下复合操作符:“AND”、“OR” 以及 “NOT”。比如说 name BEGINSWITH ‘J’ AND age >= 32;
  • 包含操作符 IN,比如说 name IN {‘Lisa’, ‘Spike’, ‘Hachi’};
  • ==、!=支持与 nil 比较,比如说 Results<Company>().filter("ceo == nil")。注意到这只适用于有关系的对象,这里 ceo 是 Company 模型的一个属性。
  • ANY 比较,比如说 ANY student.age < 21
  • 注意,虽然我们不支持复合表达式类型(aggregate expression type),但是我们支持对对象的值使用 BETWEEN 操作符类型。比如说,Results<Person>.filter("age BETWEEN %@", [42, 43]])。

11,查询结果的排序
1
2
//查询花费超过10元的消费记录,并按升序排列
consumeItems = realm.objects( ConsumeItem . self ). filter ( "cost > 10" ).sorted(byKeyPath:  "cost" )

12,使用List实现一对多关系
List  中可以包含简单类型的   Object,表面上和可变的   Array  非常类似。
注意:List 只能够包含 Object 类型,不能包含诸如String之类的基础类型。 
如果打算给我们的 Person 数据模型添加一个“dogs”属性,以便能够和多个“dogs”建立关系,也就是表明一个 Person 可以有多个 Dog,那么我们可以声明一个List类型的属性:
1
2
3
4
5
6
7
8
9
10
class   Person :  Object   {
     ...  // 其余的属性声明
     let   dogs =  List < Dog >()
}
 
// 这里我们就可以使用已存在的狗狗对象来完成初始化
let   aPerson =  Person (value: [ "李四" , 30, [aDog, anotherDog]])
 
// 还可以使用多重嵌套
let   aPerson =  Person (value: [ "李四" , 30, [[ "小黑" , 5], [ "旺财" , 6]]])
可以和之前一样,对 List 属性进行访问和赋值:
1
2
3
let   someDogs = realm.objects( Dog . self ). filter ( "name contains '小白'" )
ZhangSan .dogs.append(objectsIn: someDogs)
ZhangSan .dogs.append(dahuang)

反向关系(Inverse Relationship)
通过反向关系(也被称为反向链接( backlink)),您可以通过一个特定的属性获取和给定对象有关系的所有对象。 Realm 提供了“链接对象 ( linking objects)” 属性来表示这些反向关系。借助链接对象属性,您可以通过指定的属性来获取所有链接到指定对象的对象。
例如,一个 Dog 对象可以拥有一个名为 owners 的链接对象属性,这个属性中包含了某些 Person 对象,而这些 Person 对象在其 dogs 属性中包含了这一个确定的 Dog 对象。您可以将 owners 属性设置为   LinkingObjects  类型,然后指定其关系,说明其当中包含了 Person 对象。
1
2
3
4
5
6
7
8
class   Dog :  Object   {
     @objc   dynamic   var   name =  ""
     @objc   dynamic   var   age = 0
     
     // Realm 并不会存储这个属性,因为这个属性只定义了 getter
     // 定义“owners”,和 Person.dogs 建立反向关系
     let   owners =  LinkingObjects (fromType:  Person . self , property:  "dogs" )
}

13,添加主键(Primary Keys) 
重写   Object.primaryKey() 可以设置模型的主键。
声明主键之后,对象将被允许查询,更新速度更加高效,并且要求每个对象保持唯一性。
一旦带有主键的对象被添加到 Realm 之后,该对象的主键将不可修改。
1
2
3
4
5
6
7
8
class   Person :  Object   {
     @objc   dynamic   var   id = 0
     @objc   dynamic   var   name =  ""
     
     override   static   func   primaryKey() ->  String ? {
         return   "id"
     }
}

14,添加索引属性(Indexed Properties)
重写   Object.indexedProperties() 方法可以为数据模型中需要添加索引的属性建立索引:
1
2
3
4
5
6
7
8
class   Book :  Object   {
     @objc   dynamic   var   price = 0
     @objc   dynamic   var   title =  ""
     
     override   static   func   indexedProperties() -> [ String ] {
         return   [ "title" ]
     }
}

15,设置忽略属性(Ignored Properties)
重写  Object.ignoredProperties()  可以防止 Realm 存储数据模型的某个属性。Realm 将不会干涉这些属性的常规操作,它们将由成员变量( var)提供支持,并且您能够轻易重写它们的 setter 和 getter。
1
2
3
4
5
6
7
8
9
10
11
12
class   Person :  Object   {
     @objc   dynamic   var   tmpID = 0
     var   name:  String   {  // 计算属性将被自动忽略
         return   "\(firstName) \(lastName)"
     }
     @objc   dynamic   var   firstName =  ""
     @objc   dynamic   var   lastName =  ""
     
     override   static   func   ignoredProperties() -> [ String ] {
         return   [ "tmpID" ]
     }
}

16,修改更新数据 
(1)直接更新内容
1
2
3
4
// 在一个事务中更新对象
try! realm.write {
   consumeItem.name =  "去北京旅行"
}
(2)通过主键更新
如果您的数据模型中设置了主键的话,那么您可以使用   Realm().add(_:update:) 来更新对象(当对象不存在时也会自动插入新的对象。)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/****** 方式1 ***/
// 创建一个带有主键的“书籍”对象,作为事先存储的书籍
let   cheeseBook =  Book ()
cheeseBook.title =  "奶酪食谱"
cheeseBook.price = 9000
cheeseBook.id = 1
 
// 通过 id = 1 更新该书籍
try! realm.write {
     realm.add(cheeseBook, update:  true )
}
 
/****** 方式2 ***/
// 假设带有主键值 `1` 的“书籍”对象已经存在
try! realm.write {
     realm.create( Book . self , value: [ "id" : 1,  "price" : 22], update:  true )
     // 这本书的`title`属性不会被改变
}
(3)键值编码 
这个是在运行时才能决定哪个属性需要更新的时候,这个对于大量更新的对象极为有用。
1
2
3
4
5
6
7
let   persons = realm.objects( Person . self )
try! realm.write {
     // 更新第一个
     persons.first?.setValue( true , forKeyPath:  "isFirst" )
     // 将每个人的 planet 属性设置为“地球”
     persons.setValue( "地球" , forKeyPath:  "planet" )
}

17,删除数据
1
2
3
4
5
6
let   cheeseBook = ...  // 存储在 Realm 中的 Book 对象
 
// 在事务中删除一个对象
try! realm.write {
   realm.delete(cheeseBook)
}
也能够删除数据库中的所有数据
1
2
3
4
// 从 Realm 中删除所有数据
try! realm.write {
   realm.deleteAll()
}

18,Realm数据库配置 
(1)修改默认的的数据库
通过调用   Realm() 来初始化以及访问我们的   realm  变量。其指向的是应用的   Documents  文件夹下的一个名为“ default.realm”的文件。
通过对默认配置进行更改,我们可以使用不同的数据库。比如给每个用户帐号创建一个特有的 Realm 文件,通过切换配置,就可以直接使用默认的 Realm 数据库来直接访问各自数据库:
1
2
3
4
5
6
7
8
9
10
func   setDefaultRealmForUser(username:  String ) {
     var   config =  Realm . Configuration ()
     
     // 使用默认的目录,但是使用用户名来替换默认的文件名
     config.fileURL = config.fileURL!.deletingLastPathComponent()
         .appendingPathComponent( "\(username).realm" )
     
     // 将这个配置应用到默认的 Realm 数据库当中
     Realm . Configuration .defaultConfiguration = config
}
(2)打包进项目里的数据库的使用
如果需要将应用的某些数据(比如配置信息,初始化信息等)打包到一个   Realm  文件中,作为主要   Realm  数据库的扩展,操作如下:
1
2
3
4
5
6
7
8
9
10
11
let   config =  Realm . Configuration (
     // 获取需要打包文件的 URL 路径
     fileURL:  Bundle .main.url(forResource:  "MyBundledData" , withExtension:  "realm" ),
     // 以只读模式打开文件,因为应用数据包并不可写
     readOnly:  true )
 
// 通过配置打开 Realm 数据库
let   realm = try!  Realm (configuration: config)
 
// 通过配置打开 Realm 数据库
let   results = realm.objects( Dog . self ). filter ( "age > 5" )
(3)内存数据库
内存数据库在每次程序运行期间都不会保存数据。但是,这不会妨碍到   Realm  的其他功能,包括查询、关系以及线程安全。 假如您需要灵活的数据读写但又不想储存数据的话,那么内存数据库对您来说一定是一个不错的选择。
1
let   realm = try!  Realm (configuration:  Realm . Configuration (inMemoryIdentifier:  "MyInMemoryRealm" ))

19,加密数据库 
(1)加密后的   Realm文件不能跨平台使用(因为   NSFileProtection  只有   iOS  才可以使用) 
(2) Realm  文件不能在没有密码保护的   iOS  设备中进行加密。为了避免这些问题(或者您想构建一个   OS X 的应用),可以使用   Realm  提供的加密方法。 
(3)加密过的   Realm  只会带来很少的额外资源占用(通常最多只会比平常慢10%)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*****   在创建 Realm 数据库时采用64位的密钥对数据库文件进行 AES-256+SHA2 加密   ****/
// 产生随机密钥
var   key =  Data (count: 64)
_ = key.withUnsafeMutableBytes { bytes  in
     SecRandomCopyBytes (kSecRandomDefault, 64, bytes)
}
         
// 打开加密文件
let   config =  Realm . Configuration (encryptionKey: key)
let   realm: Realm
do {
     realm = try  Realm (configuration: config)
} catch  let   error  as   NSError   {
     // 如果密钥错误,`error` 会提示数据库不可访问
     fatalError( "Error opening realm: \(error)" )
}
 
// 和往常一样使用 Realm 即可
let   dogs = realm.objects( Book . self ). filter ( "name contains 'Fido'" )

20,数据迁移(Migration)
(1)为何要迁移
比如原来有如下   Person  模型:
1
2
3
4
5
class   Person :  Object   {
     @objc   dynamic   var   firstName =  ""
     @objc   dynamic   var   lastName =  ""
     @objc   dynamic   var   age = 0
}
假如我们想要更新数据模型,给它添加一个   fullname  属性, 而不是将“姓”和“名”分离开来。
1
2
3
4
class   Person :  Object   {
     @objc   dynamic   var   fullName =  ""
     @objc   dynamic   var   age = 0
}
在这个时候如果您在数据模型更新之前就已经保存了数据的话,那么   Realm  就会注意到代码和硬盘上数据不匹配。 每当这时,您必须进行数据迁移,否则当您试图打开这个文件的话   Realm  就会抛出错误。  

(2)如何进行数据迁移
假设我们想要把上面所声明   Person  数据模型进行迁移。如下所示是最简单的数据迁移的必需流程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 在(application:didFinishLaunchingWithOptions:)中进行配置
 
let   config =  Realm . Configuration (
   // 设置新的架构版本。这个版本号必须高于之前所用的版本号
   // (如果您之前从未设置过架构版本,那么这个版本号设置为 0)
   schemaVersion: 1,
 
   // 设置闭包,这个闭包将会在打开低于上面所设置版本号的 Realm 数据库的时候被自动调用
   migrationBlock: { migration, oldSchemaVersion  in
     // 目前我们还未进行数据迁移,因此 oldSchemaVersion == 0
     if   (oldSchemaVersion < 1) {
       // 什么都不要做!Realm 会自行检测新增和需要移除的属性,然后自动更新硬盘上的数据库架构
     }
   })
 
// 告诉 Realm 为默认的 Realm 数据库使用这个新的配置对象
Realm . Configuration .defaultConfiguration = config
 
// 现在我们已经告诉了 Realm 如何处理架构的变化,打开文件之后将会自动执行迁移
let   realm = try!  Realm ()
虽然这个迁移操作是最精简的了,但是我们需要让这个闭包能够自行计算新的属性(这里指的是   fullName),这样才有意义。 在迁移闭包中,我们能够调用 Migration().enumerateObjects(_:_:) 来枚举特定类型的每个 Object 对象,然后执行必要的迁移逻辑。注意,对枚举中每个已存在的   Object  实例来说,应该是通过访问   oldObject  对象进行访问,而更新之后的实例应该通过   newObject  进行访问:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 在 application(application:didFinishLaunchingWithOptions:) 中进行配置
 
Realm . Configuration .defaultConfiguration =  Realm . Configuration (
   schemaVersion: 1,
   migrationBlock: { migration, oldSchemaVersion  in
     if   (oldSchemaVersion < 1) {
       // enumerateObjects(ofType:_:) 方法遍历了存储在 Realm 文件中的每一个“Person”对象
       migration.enumerateObjects(ofType:  Person .className()) { oldObject, newObject  in
         // 将名字进行合并,存放在 fullName 域中
         let   firstName = oldObject![ "firstName" ]  as !  String
         let   lastName = oldObject![ "lastName" ]  as !  String
         newObject![ "fullName" ] =  "\(firstName) \(lastName)"
       }
     }
   })

21,使用带有 REST API 功能的 Realm 数据库示例
我们将从 豆瓣FM的API 那里获取一组   JSON  格式的频道数据,然后将它以   Realm Objects  的形式储存到默认的   Realm  数据库里。 
(1)json数据格式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{  
  "channels": [
         {
             "name_en": "Personal Radio",
             "seq_id": 0,
             "abbr_en": "My",
             "name": "私人兆赫",
             "channel_id": 0
         },
         {
             "name": "华语",
             "seq_id": 0,
             "abbr_en": "",
             "channel_id": "1",
             "name_en": ""
         },
         {
             "name": "欧美",
             "seq_id": 1,
             "abbr_en": "",
             "channel_id": "2",
             "name_en": ""
         }
     ]
}
(2)我们将直接把   Dictionary  插入到   Realm  中,然后让   Realm  自行快速地将其映射到   Object  上。
(从   iOS9 起,新特性要求App访问网络请求,要采用 HTTPS 协议。直接请求HTTP数据会报错,解决办法可以参照的我另一篇文章: Swift - 网络请求报App Transport Security has blocked a cleartext错)
为了确保示例能够成功,我们需要一个所有属性完全匹配   JSON  键结构的   Object  结构体。如果   JSON  的键结构不匹配   Object  结构体属性结构的话,那么就会在插入时被忽略。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import   UIKit
import   RealmSwift
 
class   ViewController :  UIViewController   {
     
     override   func   viewDidLoad() {
         super .viewDidLoad()
         
         // 调用API
         let   url =  URL (string:  "http://www.douban.com/j/app/radio/channels" )!
         let   response = try!  Data (contentsOf: url)
         
         // 对 JSON 的回应数据进行反序列化操作
         let   json = try!  JSONSerialization .jsonObject(with: response,
                                          options: .allowFragments)  as ! [ String : Any ]
         let   channels = json[ "channels" ]  as ! [[ String : Any ]]
         
         let   realm = try!  Realm ()
         try! realm.write {
             // 为数组中的每个元素保存一个对象(以及其依赖对象)
             for   channel  in   channels {
                 if   channel[ "seq_id" ]  as !  Int   == 0 { continue }  //第一个频道数据有问题,丢弃掉
                 realm.create( DoubanChannel . self , value: channel, update:  true )
             }
         }
         
         print (realm.configuration.fileURL ??  "" )
     }
     
     override   func   didReceiveMemoryWarning() {
         super .didReceiveMemoryWarning()
     }
}
 
//豆瓣频道
class   DoubanChannel : Object   {
     //频道id
     @objc   dynamic   var   channel_id =  ""
     //频道名称
     @objc   dynamic   var   name =  ""
     //频道英文名称
     @objc   dynamic   var   name_en =  ""
     //排序
     @objc   dynamic   var   seq_id = 0
     @objc   dynamic   var   abbr_en =  ""
     
     //设置主键
     override   static   func   primaryKey() ->  String ? {
         return   "channel_id"
     }
}

(3)可以看到数据已经成功插入到库中了
原文:Swift - Realm数据库的使用详解(附样例)


22,当前版本的限制
Realm  致力于平衡数据库读取的灵活性和性能。为了实现这个目标,在   Realm  中所存储的信息的各个方面都有基本的限制。例如:
(1)类名称的长度最大只能存储   57  个   UTF8  字符。
(2)属性名称的长度最大只能支持   63  个   UTF8  字符。
(3) NSData  以及   String  属性不能保存超过   16 MB  大小的数据。如果要存储大量的数据,可通过将其分解为16MB 大小的块,或者直接存储在文件系统中,然后将文件路径存储在 Realm 中。如果您的应用试图存储一个大于 16MB 的单一属性,系统将在运行时抛出异常。
(4)对字符串进行排序以及不区分大小写查询只支持“基础拉丁字符集”、“拉丁字符补充集”、“拉丁文扩展字符集 A” 以及”拉丁文扩展字符集 B“(UTF-8 的范围在 0~591 之间)。

原文出自: www.hangge.com   原文链接: http://www.hangge.com/blog/cache/detail_891.html
Realm_Building_Modern_Swift_Apps_with_Realm_Database_v1.0 立即下载

相关推荐

Redis【实战篇】---- 分布式锁-redission

重入问题:重入问题是指 获得锁的线程可以再次进入到相同的锁的代码块中,可重入锁的意义在于防止死锁,比如HashTable这样的代码中,他的方法都是使用synchronized修饰的,假如他在一个方法内,调用另一个方法,那么此时如果是不可重入的,不就死锁了吗?所以可重入锁他的主要意义是防止死锁,我们的synchronized和Lock锁都是可重入的。不可重试:是指目前的分布式只能尝试一次,我们认为合理的情况是:当线程在获得锁失败后,他应该能再次尝试获得锁。

是微风,是晚霞,是无可替代 1万+

Realm Swift入门指南:构建高性能移动数据库应用

本文全面介绍了Realm Swift的核心特性、安装配置、数据模型定义以及基础CRUD操作。Realm Swift作为专为移动应用设计的高性能数据库解决方案,提供了面向对象的数据模型、实时数据更新、卓越的查询性能和数据加密等强大功能。文章详细讲解了四种集成方式(SPM、CocoaPods、Carthage和手动集成)的优缺点比较,深入探讨了数据模型定义、对象关系管理和事务处理的最佳实践,为开发者提...

gitblog_00011的博客 1092

CCS20实战入门:第一个工程搭建示例

通过实际操作演示如何在ccs20中创建并配置首个开发项目,涵盖环境设置与基础调试步骤,帮助新手快速上手ccs20集成开发环境,提升嵌入式开发效率。

weixin_31185473的博客 884

swift必知必会之数据库框架-Realm

swift-Realm

jacknian的专栏 1365

告别GIS软件!用R语言ggplot2+ggmapcn绘制出版级世界地图(附5种投影对比图)

本文提供了一份完整的实践指南,教你如何利用R语言及其强大的ggplot2生态系统,结合ggmapcn包,绘制出出版级的世界地图。文章详细对比了五种经典地图投影(如摩尔维德、罗宾森投影)的代码实现与视觉差异,并讲解了如何添加比例尺、指北针等专业元素,最终导出高清PDF,实现从数据分析到专业可视化的全流程代码化操作,彻底告别传统GIS软件。

p5l2m9n4o6q的博客 407

[c语言]用辗转相除法求最大公约数,递归和不递归两种

在c语言的学习中必然会遇到求两个数之间的最大公约数的题目,那么对于其他经典方法,最简便快捷的方式就是利用辗转相除法 辗转相除法又叫做欧几里得算法,目的是为了求两个正整数的最大公约数 定理:gcd(a,b) = gcd(b ,a%b) //在这里用(a,b)表示a和b的最大公约数证明:a可以表示成a = kb + r,则r = a %b 假设d是a,b的一个公约数,则有 d|a, d|b,而r = a - kb,因此d|r //这里的"|"的意思是 :d是b的因数 ,d是a的因数 因此d...

ZZRBlogger的博客 1万+

iOS-Swift之Realm的使用教程

·版本:Realm Swift 3.15.0 ·使用要求 ·安装 ·models模型 ·realm对象操作 ·writes写 ·queries读 ·update更新 ·delete删除 ·migration数据迁移

amberoot's Space 3663

【数据分析/商业分析】面试题整理——SQL专题

数据分析\商业分析—面试题整理 自己总结的SQL类的面试题 文章目录数据分析\商业分析—面试题整理1.新增用户2.活跃用户数量3.连续登录4.次(n)日留存5.每个科目下分数最高的两名学生

awater_17的博客 1859

IOS DB存储之Realm.swift (二) 使用详解

IOS DB存储之Realm.swift 使用详解1. Realm简介2. Realm安装配置3. Realm数据迁移4. Realm加密5. Realm基本使用6. Realm使用注意 1. Realm简介 2. Realm安装配置 3. Realm数据迁移 4. Realm加密 5. Realm基本使用 6. Realm使用注意 ...

kyl282889543的博客 2075

Cadence学习之路(六)元器件封装绘制

使用Allegro PCB Designer绘制元器件封装

qq_46757048的博客 1万+

基于江协科技STM32创建HAL库工程模板

基于江协科技STM32入门教程创建的HAL库工程模板

2401_82728381的博客 1133

IOS DB存储之Realm.swift (一) 使用篇

@[TOC](IOS DB存储之Realm.swift (一) 使用篇)

kyl282889543的博客 1006

T型三电平逆变器中点电位平衡详解

T型三电平逆变器(T-type Three-Level Inverter)是一种高效的多电平拓扑,相比传统NPC(Neutral Point Clamped)三电平逆变器,具有更低的开关损耗、更高效率和更简单的结构,尤其适用于中功率应用(如光伏逆变器、风电变换器和工业驱动)。(T-type Three-Level Inverter)中的应用已成为当前中高压功率变换领域(如光伏逆变器、储能PCS、电动汽车充电桩、风电并网和工业驱动)的热门方案。针对 T型逆变器,类似 NPC 的零序注入法适用。

专注于前沿技术的探索与实践,热衷于从代码逻辑、架构设计到行业应用等多维度深挖技术本质。期待在技术之路上与你共同成长~ 545

Realm-Swift使用入门

Realm适用iOS和Android平台,本身相比sqlite、CoreData操作简单,在这里记录下使用方式; (Swift4.2) 安装 pod 'RealmSwift' 基础使用 打开 Realm 数据库 要打开一个 Realm 数据库,首先需要初始化一个新的 Realm 对象: let realm = try! Realm() try! realm.write { realm.a...

weixin_34405332的博客 1173

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Realm Swift

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs.com/strengthen/)➤GitHub地址:https://github.com/strengthen/LeetCode➤原文地址:https://www.cnblogs.com/streng...

weixin_30344795的博客 635

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Swift-Realm数据库的使用详解

Swift-Realm数据库的使用详解 概述 Realm 是一个跨平台的移动数据库引擎,其性能要优于 Core Data 和 FMDB - 移动端数据库性能比较, 我们可以在 Android 端 realm-java,iOS端:Realm-Cocoa,同时支持 OC 和 Swift两种语言开发。其使用简单,免费,性能优异,跨平台的特点广受程序员GG喜爱。 Realm 中文文档 ...

极客学伟的技术分享社区 7151

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

android realm数据库,浅谈Realm数据库及其使用

1.Realm介绍realm是一个跨平台移动数据库引擎,支持iOS、OS X(Objective-C和Swift)以及Android。目前还支持React Native 和 Xamarin。2014年7月发布。由YCombinator孵化的创业团队历时几年打造,是第一个专门针对移动平台设计的数据库。目标是取代SQLite。为了彻底解决性能问题,核心数据引擎C++打造,并不是建立在SQLite之上的...

weixin_42639633的博客 1101

iOS开发 Swift中使用Realm数据

iOS开发 Realm数据的使用

weixin_38934440的博客 909

iOS Realm数据库的基本用法

简介 Realm是由&nbsp;Y Combinator&nbsp;公司孵化的一款支持运行在移动设备上的旨在取代 CoreData 和 Sqlite 的嵌入式数据库。它拥有自己的数据库存储引擎,可以高效且快速地完成数据库的构建操作。 Realm可以轻松地移植到项目当中,并且绝大部分常用的增删查改功能,都可以用一行简单的代码轻松完成!目前支持Objective-C、Swift和Java三种语...

qq_27501365的博客 4892

Realm 数据库使用

Table of Contents(目录) 0. 项目描述 1. Realm模型 2. Realm数据库安装 3. 创建Model 4. 实现CreateRandomDatabase函数创建初始数据库 创建数据库、删除数据库 创建Model实例,修改Model实例,删除Model实例,增、删、改操作 查询Model,查询、排序、分页操作 5. 数据库结构更新,迁移 6. 数据绑...

庞兴庆的魔法屋 1036

Swift语言的数据库编程

在现代应用程序的开发中,数据的存储和管理是一个至关重要的环节。无论是移动应用、Web服务还是桌面软件,数据库都扮演着数据存储和检索的核心角色。随着Swift语言在iOS和macOS开发中的普及,越来越多的开发者开始关注如何使用Swift进行数据库编程。本文将深入探讨Swift语言的数据库编程,包括常见数据库的选择、与数据库的连接、数据的增删查改(CRUD)操作、ORM(对象关系映射)工具的使用,以及性能优化等方面。

2401_90031998的博客 1070

Swift Composable Architecture数据库集成:CoreData和Realm支持

在iOS/macOS应用开发中,数据持久化是每个开发者必须面对的核心问题。你是否曾经遇到过: - 状态管理混乱,业务逻辑与数据存储耦合严重 - 数据库操作代码分散在各个ViewController中 - 难以进行单元测试和集成测试 - 数据同步和状态一致性维护困难 Swift Composable Architecture(TCA)通过其强大的状态管理和副作用处理能力,为数据库集成提供了优雅的...

gitblog_00471的博客 1201
上一篇: iOS App打包上架详细流程
下一篇: iOS一行代码移除子视图,或者layer。iOS获取近八天日期数组
Cao_Shixin攻城狮
博客等级 码龄10年 710粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值