はじめに
RealmモデルをApple Watchに直接送信することはできないようです。
Codable
属性を指定して、JSON等にエンコードすることで送信することができます。
エンコード方法については記事1の補足になります。
ただし、Realmのバージョンが変わったことで若干仕様が変わっているようなので、本記事ではRealm ver.10.34.1現在での情報ということでご参考にしていただければと思います。
エンコード方法
まずモデルを定義します。
import Foundation
import RealmSwift
class Album: Object, Codable {
@Persisted var id: String = UUID().uuidString
@Persisted var name: String = ""
@Persisted var content = RealmSwift.List<ImageInfo>()
override public static func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
case content
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(content, forKey: .content)
}
}
また
import Foundation
import RealmSwift
class ImageInfo: Object, Codable {
@Persisted var id: String = UUID().uuidString
@Persisted var name: String = ""
@Persisted var savePath: String = ""
override public static func primaryKey() -> String? {
return "id"
}
private enum CodingKeys: String, CodingKey {
case id
case name
case savePath
}
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id)
try container.encode(name, forKey: .name)
try container.encode(savePath, forKey: .savePath)
}
}
Album
モデルのコンテンツとしてImageInfo
を持っているモデルを定義してみました。
各モデルにCodable
属性が指定されています。両方のモデルに必要なことに注意してください。
そうすることで、こういった入れ子構造のモデルもJSON化可能です。
では、実際にエンコードしていきます。
(今回はrealm.objects()
ですべてのオブジェクトを取得し、それぞれについてエンコードしてArrayに追加&Array自体をさらにエンコードする、という形にしました)
// 読み込み&encode処理
let realm = try! Realm()
let albums: List = realm.objects(Album.self)
do{
var dataArray: [Data] = []
for album in albums {
let albumData = try JSONEncoder().encode(album)
dataArray.append(albumData)
}
let dataArrayEncoded = try JSONEncoder().encode(dataArray)
}catch{
print(error)
}
Watch側でデコードしてRealmに保存するコードは以下です。
// decode&保存処理
do{
let realm = try Realm()
let dataArray = try JSONDecoder().decode([Data].self, from: dataArrayEncoded)
for data in dataArray{
let album = try JSONDecoder().decode(Album.self, from: data)
try realm.write() {
realm.add(album, update: .modified) // データが無ければ追加、あったら上書き
}
}
}catch{
print("decode error")
print(error)
}
Watch側で保存したDBを覗くと以下のようになります。
let realm = try! Realm()
let albums = realm.objects(Album.self)
print(albums)
↓
[Album {
id = 6342D5AD-339B-4876-8644-C6704A7A2ABF;
name = All;
content = List<ImageInfo> <0x6000020013f0> (
[0] ImageInfo {
id = 62C40A75-C52A-4CA4-BEA8-9A3D65FF8A33;
name = image;
savePath = file:///xxx.jpg;
},
[1] ImageInfo {
id = 605AECA6-8CAD-4461-B7DD-F88F91EBA0D9;
name = image;
savePath = file:///xxx.jpg;
},
[2] ImageInfo {
id = B31D5527-57B2-4F13-B1A8-7DB1A2FB068A;
name = image;
savePath = file:///xxx.jpg;
}
);
}, Album {
id = AACD238E-3941-40E5-9DBB-C242532F488C;
name = New;
content = List<ImageInfo> <0x600002008c60> (
[0] ImageInfo {
id = 605AECA6-8CAD-4461-B7DD-F88F91EBA0D9;
name = image;
savePath = file:///xxx.jpg;
},
[1] ImageInfo {
id = B31D5527-57B2-4F13-B1A8-7DB1A2FB068A;
name = image;
savePath = file:///xxx.jpg;
}
);
}]
エンコード処理を以下のようにしないのか?と思うかもしれません。
let albumData = try Album.encode(to: JSONEncoder())
せっかくAlbum
モデルで定義したencode
を使っていないので「あれ?」となるのですが、上の例だと、以下のようなエラーになります。
argument type 'jsonencoder' does not conform to expected type 'encoder'
これにはJSONEncoder()の定義が起因しているようです。2 3
送信方法
JSONエンコードすれば、Data
型になるので、Watch ConnectivityのsendMessageData()
等で送ることができます。