質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

AppleWatch

AppleWatchは、iPhoneと連動して動作する時計型のデバイスです。時間の確認だけでなく、通話や受信メールの確認などを行うことができます。

Q&A

解決済

2回答

2616閲覧

Realmを使ったデータの送受信が出来ない

lahlah

総合スコア16

Realm

RealmとはSQLiteやCore Dataに代わるモバイルデータベースです。iOSとAndroidの両方でサポートされています。

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

iPhone

iPhoneとは、アップル社が開発・販売しているスマートフォンです。 同社のデジタルオーディオプレーヤーiPodの機能、電話機能、インターネットやメールなどのWeb通信機能の3つをドッキングした機器です。

AppleWatch

AppleWatchは、iPhoneと連動して動作する時計型のデバイスです。時間の確認だけでなく、通話や受信メールの確認などを行うことができます。

0グッド

0クリップ

投稿2019/11/25 09:47

編集2019/11/26 06:02

前提・実現したいこと

iPhoneの Realmデータを Apple Watchに送るプログラムを考えています.
各デバイスにアプリをインストールすることは出来ましたが、データの送受信が上手く行きません.

何が不足しているのでしょうか?
ご回答よろしくお願いします.

発生している問題・エラーメッセージ

watchOSのプログラムを実行した時に以下のエラーメッセージが出ます.

Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.'

追記 11/26
watchOS プログラムの
let realm = try! Realm()
をrealmデータを取得する関数の中に持って行ったところ、上記のエラーは解消されましたが、代わりに以下のエラーが発生します.

Fatal error: 'try!' expression unexpectedly raised an error: Error Domain=io.realm Code=2 "Unable to open a realm at path '/var/mobile/Containers/Data/PluginKitPlugin/E7F03F8B-86D4-42AF-AC8A-A1F2B2E27780/Documents/Inbox/com.apple.watchconnectivity/AFBC4FDB-28C3-4D55-A833-1E5F59DA0C4B/Files/F39F9FCD-AA0E-48B8-897D-E67AF8D2D043/default.realm.management': make_dir() failed: Operation not permitted Path:Exception backtrace:

該当のソースコード

iOSのプログラム

swift

1import UIKit 2import RealmSwift 3import WatchConnectivity 4 5class ViewController: UIViewController, WCSessionDelegate { 6 let realm = try! Realm() 7 let get = cData() 8 9 override func viewDidLoad() { 10 super.viewDidLoad() 11 // Do any additional setup after loading the view. 12 13 get.name = "abc" 14 get.memo = "def" 15 16 try! realm.write { 17 realm.add(get) 18 } 19 20 print("for iPhone") 21 print(get.name) 22 print(get.memo) 23 24 //データの追加 25 try! realm.write { 26 get.name = get.name + "ghi" 27 } 28 29 30 if WCSession.isSupported() { 31 let session = WCSession.default 32 session.delegate = self 33 session.activate() 34 } 35 36 } 37 38 //ボタン押したらデータ送信 39 @IBAction func sending(_ sender: UIButton) { 40 //realmデータを送る 41 if let path = Realm.Configuration().fileURL { 42 WCSession.default.transferFile(path, metadata: nil) 43 print("send data to Apple Watch") 44 } 45 } 46 47 48 @available(iOS 13.1, *) 49 func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { 50 print("activation did complete!\n") 51 } 52 53 func sessionDidBecomeInactive(_ session: WCSession) { 54 print("session did become inactive") 55 } 56 57 func sessionDidDeactivate(_ session: WCSession) { 58 print("session did deactivate") 59 } 60 61}

watchOSのプログラム

swift

1import WatchKit 2import Foundation 3import RealmSwift 4import WatchConnectivity 5 6class InterfaceController: WKInterfaceController, WCSessionDelegate { 7 override func awake(withContext context: Any?) { 8 super.awake(withContext: context) 9 10 // Configure interface objects here. 11 if WCSession.isSupported() { 12 let session = WCSession.default 13 session.delegate = self 14 session.activate() 15 } 16 } 17 18 19 @available(watchOS 6.0, *) 20 func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { 21 print("watch activation did completed") 22 } 23 24 //realmデータを取得する関数 25 func session(_ session: WCSession, didReceive file: WCSessionFile) { 26 var config = Realm.Configuration() 27 config.fileURL = file.fileURL 28 Realm.Configuration.defaultConfiguration = config 29 30 let realm = try! Realm() 31 let text = realm.objects(cData.self) 32 print("memo: (text[0].memo)") 33 print("name: (text[0].name)") 34 } 35 36 37 override func willActivate() { 38 // This method is called when watch view controller is about to be visible to user 39 super.willActivate() 40 41 } 42 43 override func didDeactivate() { 44 // This method is called when watch view controller is no longer visible 45 super.didDeactivate() 46 } 47 48}

試したこと

同様の事例がないか調べましたが、似た事例はあるものの今回のエラーの解決につながるようなものが未だ見つかりません.

補足情報(FW/ツールのバージョンなど)

バージョン
Xcode 11.1, Swift5.0.1
iPhoneX, Apple Watch Series4

・let realm = try! Realm()
をrealmデータを取得する関数内に書くようにしたところ、iOSのプログラムを実行すればボタンを押した時にコンソールに "send data to Apple Watch" は出力されるようになりました.

・watchOSのプログラムを実行した時は、"watch activation did completed" がコンソールに出力された後、エラーメッセージが表示されます.

・WatchConnectivityの使い方を知るために、Apple公式サイトを参考にしましたが、このサイトの Get Started の手順5.6がいまいちよく分からなかったため、正しい手順を踏めていないことが今回のエラーにつながっているのかもしれません.

手順5については、プロジェクトにSettings-Watch.bundleを追加し、Root.plistのApplicationGroupContainerIdentifierをApp groupsで作成したグループ名にしました.
手順6については、TestDataProvider classがどこにあるのか分からなかったため、何もしませんでした.

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

下記の実行スレッドが異なっていませんか。

Swift

1let realm = try! Realm()

Swift

1let text = realm.objects(cData.self)

Xcode - Documentationより

optional func session(_ session: WCSession, didReceive file: WCSessionFile)
Discussion
This method is called on a background thread of your app.
(Google翻訳)
このメソッドは、アプリのバックグラウンドスレッドで呼び出されます。

投稿2019/11/25 10:13

dsuzuki

総合スコア1682

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

lahlah

2019/11/26 05:23

ご回答ありがとうございます. let realm = try! Realm() をrealmデータを取得する関数内に入れたところ、incorrect threadエラーは解消されたのですが、エラーメッセージに追記いたしました別のエラーが発生してしまいました. 追記のエラーの原因は何でしょうか...? 教えていただけると有難いです.
lahlah

2019/11/26 06:08

ありがとうございます. 教えていただいたサイトの >そうなると、設定.appの自分のキーボードのところが先に進めるようになっているはず という箇所が上手く行きません... RequestOpenAccessをYESにしても、先に進めるようになりません. realmデータのpathの生成方法が参考サイトと自分のプログラムで異なりますが、それが原因でしょうか...?
dsuzuki

2019/11/26 07:31

結局はこれかなぁ https://teratail.com/questions/221374 > 色々調べてみましたが、WatchConnectivityをimportしてiPhoneにデータを送る以外に、Apple Watchのデータにアクセスする方法は見当たりませんでした.
lahlah

2019/11/26 08:51

Realmデータを送るより、SendMessageやtransferFileを使った方が良いということでしょうか?
dsuzuki

2019/11/26 09:27

こっちの問題かな。 --------- Xcode - Documentationより Important Remember to move the file referenced by the file parameter if you intend to keep it. If you do not move the file synchronously during your implementation of this method, the system deletes the file when the method returns. (Google翻訳) 重要 保持する場合は、fileパラメーターによって参照されるファイルを移動することを忘れないでください。 このメソッドの実装中にファイルを同期的に移動しない場合、メソッドが戻るときにシステムはファイルを削除します。 --------- 現在のPathは操作が許可されていない(Operation not permitted Path)ので、許可されているフォルダに移動すればいいのではないでしょうか。
lahlah

2019/11/26 09:43

ありがとうございます. ちょうど参考になるサイトが見つかり、書き込みが許可されているディレクトリにコピーして開く必要があるということが分かり、コメントでご指摘いただいた通り、許可されているディレクトリに移動する必要がありました. 初めのエラーを含め沢山アドバイスをいただき、とても参考になりました. ありがとうございました!
guest

0

自己解決

watchOSプログラムの realmデータを取得する関数を以下に修正したところ、上手くいきました.

swift

1//realmデータを取得する関数 2func session(_ session: WCSession, didReceive file: WCSessionFile) 3{ 4 var config = Realm.Configuration() 5 6 // --- 修正箇所 ↓ --- 7 let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask) 8 let documentsDirectory = paths[0] 9 let realmURL = documentsDirectory.appendingPathComponent("data.realm") 10 try! FileManager.default.copyItem(at: file.fileURL, to: realmURL) 11 12 config.fileURL = realmURL 13 // --- 修正箇所 ↑ --- 14 15 Realm.Configuration.defaultConfiguration = config 16 17 let realm = try! Realm() 18 let text = realm.objects(cData.self) 19 print("memo: (text[0].memo)") 20 print("name: (text[0].name)") 21 } 22

こちらのサイトを参考にさせていただきました.
Watch Connectivityで転送されたファイルは一旦システムが管理する特別なディレクトリに保存されます. そこでは、Realmが必要とする管理ファイルの作成が許可されていないため、読み取り専用でなければ、直接ファイルを開くことはできません.
転送されたファイルを、Documentディレクトリなど書き込み可能な場所にコピーしてから開く必要があります.

投稿2019/11/26 09:37

lahlah

総合スコア16

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問