0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Parse Server Swift SDKの使い方(データストアクエリー操作)

Posted at

ニフクラ mobile backendは3月末で終了します

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

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

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

Parse ServerにはSwift SDKとObjective-C SDKが用意されています。機能的にいうと、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をインポートします。

import ParseSwift

初期化

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

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

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 を継承した構造体を作成します。

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

    // 独自のプロパティ
    var points: Int?
    var timeStamp: Date? = Date()
    var oldScore: Int?
    var isHighest: Bool?
}

クエリーの基本形

クエリーは query メソッドを使います。引数は検索条件です。

let afterDate = Date().addingTimeInterval(-300)
var query = GameScore.query("points" > 50,
                            "createdAt" > afterDate)
    .order([.descending("points")])

クエリーの実行

クエリーの実行は find メソッドを使います。非同期での実行は以下の通りです。注意点は、検索結果がない場合 .failure になることです。

query.limit(2)
    .order([.descending("points")])
    .find(callbackQueue: .main) { results in
    switch results {
    case .success(let scores):
        scores.forEach { score in
            guard let createdAt = score.createdAt else { fatalError() }
            print("スコア: \(score)")
        }
    case .failure(let error):
        if error.equalsTo(.objectNotFound) {
            assertionFailure("検索結果はありません")
        } else {
            assertionFailure("実行エラー: \(error)")
        }
    }
}

同期での実行は以下の通りです。

let results = try query.find()
results.forEach { score in
    guard let createdAt = score.createdAt else { fatalError() }
    print("Found score: \(score)")
}

最初の1件だけを取得

最初の1件だけを取得する場合は、 first メソッドを使います。非同期での実行は以下の通りです。この場合はParseObjectが返ってきます。

query.first { results in
    switch results {
    case .success(let score):
        guard score.objectId != nil,
            let createdAt = score.createdAt else { fatalError() }
        print("スコア: \(score)")
    case .failure(let error):
        if error.containedIn([.objectNotFound, .invalidQuery]) {
            assertionFailure("検索結果がない、またはクエリーが不正です")
        } else {
            assertionFailure("実行エラー: \(error)")
        }
    }
}

結果行数も取得する

結果行数も取得する場合は、 withCount メソッドを使います。非同期での実行は以下の通りです。

query.withCount { results in
    switch results {
    case .success(let (score, count)):
        print("スコア: \(score) トータル行数: \(count)")
    case .failure(let error):
        if error.containedIn([.objectNotFound, .invalidQuery]) {
            assertionFailure("検索結果がない、またはクエリーが不正です")
        } else {
            assertionFailure("実行エラー: \(error)")
        }
    }
}

相対的な時間でのクエリー

相対的な時間でのクエリーは relative メソッドを使います。非同期での実行は以下の通りです。

let queryRelative = GameScore.query(relative("createdAt" < "in 10 minutes"))
queryRelative.find { results in
    switch results {
    case .success(let scores):
        print("検索結果: \(scores)")
    case .failure(let error):
        print("実行エラー: \(error)")
    }
}

結果のフィールドを絞り込む

select メソッドを使うと、結果のフィールドを絞り込めます。非同期での実行は以下の通りです。

let querySelect = query.select("points")
querySelect.first { results in
    switch results {
    case .success(let score):
        guard score.objectId != nil,
            let createdAt = score.createdAt else { fatalError() }
        print("検索結果: \(score)")
    case .failure(let error):
        if let parseError = error.equalsTo(.objectNotFound) {
            assertionFailure("オブジェクトがありません: \(parseError)")
        } else {
            assertionFailure("実行エラー: \(error)")
        }
    }
}

逆に取り除く場合には、 exclude メソッドを使います。非同期での実行は以下の通りです。

let queryExclude = query.exclude("points")
queryExclude.first { results in
    switch results {
    case .success(let score):

        guard score.objectId != nil,
            let createdAt = score.createdAt else { fatalError() }
        print("検索結果: \(score)")

    case .failure(let error):
        if let parseError = error.containedIn(.objectNotFound, .invalidQuery) {
            assertionFailure("オブジェクトがありません: \(parseError)")
        } else {
            assertionFailure("実行エラー: \(error)")
        }
    }
}

まとめ

以上、Parse Server Swift SDKのデータストアクエリー操作について解説しました。NCMBの検索方式とは若干異なる印象です。注意点は、検索結果がない場合にエラーになることでしょう。

とはいえParse Serverには結果フィールドの絞り込みなど、便利な機能もあります。NCMBと設計思想も似ていますので、他のmBaaSと比べても移行時の修正量はそこまで多くないと思われます。載せ替え先として検討に挙げてください。

parse-community/Parse-Swift: The Swift SDK for Parse Platform (iOS, macOS, watchOS, tvOS, Linux, Android, Windows)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?