Parse Server Swift SDKの使い方（データストアオブジェクトのCRUD操作）

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

ニフクラ mobile backendからの移行先として、お勧めしているのが[Parse Server](https://parseplatform.org/)です。設計思想が近く、変更するコード量が少なく済むのではないかと思います。

Parse ServerではiOS向けにSDKを提供していますが、Swift SDKについてはあまりドキュメントが充実していません。そこで、各機能の使い方を解説します。今回はデータストアオブジェクトの使い方です。

## Swift SDKとObjective-C SDKのどちらを使うべきか

Parse ServerにはSwift SDKと[Objective-C SDK](https://docs.parseplatform.org/ios/guide/)が用意されています。機能的にいうと、Objective-C SDKの方が多いようです。しかし、公式メッセージとしてはSwift SDKを使っていくのを奨励しています。

## Parse Server Swift SDKのインストール

Swift SDKのインストールは、CocoaPodsやCarthageなどが使えます。しかし、一番簡単なのはXcodeのPackage Dependenciesを使う方法でしょう。

XcodeのFileメニューより、Add Package Dependenciesを選択して、出てきたダイアログで以下のURLを指定します。

```
https://github.com/parse-community/Parse-Swift.git
```

そして、利用するファイルでSDKをインポートします。

```swift
import ParseSwift
```

## 初期化

SwiftUIの例です。初期化は `(アプリ名)App.swift` にて行います。そして、初期化は `ParseSwift.initialize` にて行います。指定するアプリケーションID、クライアントキー、サーバーURLはそれぞれParse Serverを立ち上げる際に指定したものを使います。

マスターキーも指定できるようですが、アプリ側では使わない方が良いかと思います。

```swift
import SwiftUI
import ParseSwift

@main
struct ParseDemoApp: App {
    init() {
        ParseSwift.initialize(applicationId: "YOUR_APP_ID", clientKey: "YOUR_CLIENT_KEY", serverURL: URL(string: "https://example.com/parse")!)
    }
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
```

## データストアオブジェクトの定義

データストアで利用するオブジェクトは `ParseObject` を継承して定義します。

```swift
struct GameScore: ParseObject {
    // 必須のプロパティ
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    var originalData: Data?

    // 独自のプロパティ
    var points: Int?

    /*:
		独自メソッド
     */
    func merge(with object: Self) throws -> Self {
        var updated = try mergeParse(with: object)
        if updated.shouldRestoreKey(\.points,
                                     original: object) {
            updated.points = object.points
        }
        return updated
    }
}
```

データストアオブジェクトの初期化時に値を設定できるようにしたい場合は、 `extension` の利用がお勧めされています。

```swift
extension GameScore {
    init(points: Int) {
        self.points = points
    }
    init(objectId: String?) {
        self.objectId = objectId
    }
}
```

## データの保存

データを保存する際には `save` メソッドを使います。非同期での保存は以下の通りです。

```swift
let score = GameScore(points: 300)
score.save { result in
		switch result {
		case .success(let item):
				print(item.objectId ?? "")
		case .failure(let error):
				print(error)
		}
}
```

同期での保存は `try` を使います。

```swift
try score.save()
```

## データの取得

objectIdが分かっている場合は、 `fetch` メソッドでデータを取得できます。

### 非同期での取得

`fetch` に対してブロックを渡すことで、非同期に処理できます。

```swift
let scoreToFetch = GameScore(objectId: "ABCDE")

scoreToFetch.fetch { result in
    switch result {
    case .success(let fetchedScore):
        print("Successfully fetched: \(fetchedScore)")
    case .failure(let error):
        assertionFailure("Error fetching: \(error)")
    }
}
```

### 同期での取得

同期処理の場合は `try` を使います。

```swift
do {
    let fetchedScore = try scoreToFetch.fetch()
    print("Successfully fetched: \(fetchedScore)")
} catch {
    assertionFailure("Error fetching: \(error)")
}
```

## データの更新

データの更新も `save` メソッドを使います。非同期、同期処理も保存時と同じです。

## データの削除

データの削除は `delete` メソッドを使います。

```swift
do {
    try score.delete()
    print("削除しました: \(score!)")
} catch {
    assertionFailure("削除失敗しました")
}
```

## まとめ

Parse ServerとNCMBのデータストア操作は、SDKの仕組みで異なる部分が多いです。載せ替える際には、コードの修正が必要になるでしょう。

とはいえ、データの管理方法などはParse ServerとNCMBで似ています。他のmBaaSと比べると、修正量はそこまで多くないと思われます。載せ替え先として検討に挙げてください。

[parse\-community/Parse\-Swift: The Swift SDK for Parse Platform \(iOS, macOS, watchOS, tvOS, Linux, Android, Windows\)](https://github.com/parse-community/Parse-Swift)