Home>

I'm thinking about a program that sends iPhone Realm data to Apple Watch.
I was able to install the app on each device, but I can't send or receive data.

What is missing?
Thanks for your reply.

Error message

When you run a watchOS program, the following error message appears.

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

Added 11/26
watchOS program
let realm = try! Realm ()
Was taken into the function to get realm data, the above error was resolved, but the following error occurs instead.

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: failed: Operation not permitted Path: Exception backtrace:
Applicable source code

iOS program

import UIKit
import RealmSwift
import WatchConnectivity
class ViewController: UIViewController, WCSessionDelegate {
    let realm = try! Realm ()
    let get = cData ()
    override func viewDidLoad () {
        super.viewDidLoad ()
        // Do any additional setup after loading the view.
        get.name = "abc"
        get.memo = "def"
        try! realm.write {
            realm.add (get)
        }
        print ("for iPhone")
        print (get.name)
        print (get.memo)
        // Add data
        try! realm.write {
            get.name = get.name + "ghi"
        }

        if WCSession.isSupported () {
            let session = WCSession.defaultsession.delegate = self
            session.activate ()
        }
    }
    // Press button to send data
    @IBAction func sending (_ sender: UIButton) {
        // Send realm data
        if let path = Realm.Configuration (). fileURL {
            WCSession.default.transferFile (path, metadata: nil)
            print ("send data to Apple Watch")
        }
    }

    @available (iOS 13.1, *)
    func session (_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print ("activation did complete! \ n")
    }
    func sessionDidBecomeInactive (_ session: WCSession) {
        print ("session did become inactive")
    }
    func sessionDidDeactivate (_ session: WCSession) {
        print ("session did deactivate")
    }
}

watchOS program

import WatchKit
import foundation
import RealmSwift
import WatchConnectivity
class InterfaceController: WKInterfaceController, WCSessionDelegate {
    override func awake (withContext context: Any?) {
        super.awake (withContext: context)
        // Configure interface objects here.
        if WCSession.isSupported () {
            let session = WCSession.default
            session.delegate = self
            session.activate ()
        }
    }@available (watchOS 6.0, *)
    func session (_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
        print ("watch activation did completed")
    }
    // Function to get realm data
    func session (_ session: WCSession, didReceive file: WCSessionFile) {
        var config = Realm.Configuration ()
        config.fileURL = file.fileURL
        Realm.Configuration.defaultConfiguration = config
        let realm = try! Realm ()
        let text = realm.objects (cData.self)
        print ("memo: \ (text [0] .memo)")
        print ("name: \ (text [0] .name)")
    }

    override func willActivate () {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate ()
    }
    override func didDeactivate () {
        // This method is called when watch view controller is no longer visible
        super.didDeactivate ()
    }
}

I looked for similar cases, but there are similar ones, but I still haven't found anything that can help resolve this error.

Supplemental information (FW/tool version etc.)

Version
Xcode 11.1, Swift5.0.1
iPhoneX, Apple Watch Series4

・ let realm = try! Realm ()
When you run the iOS program, "send data to Apple Watch" will be output to the console when you press the button.

-When a watchOS program is executed, an error message is displayed after "watch activation did completed" is output to the console.

・ To know how to use WatchConnectivity, Apple official site

For step 5, I added Settings-Watch.bundle to the project, and changed ApplicationGroupContainerIdentifier in Root.plist to the group name created in App groups.
For step 6, I didn't do anything because I didn't know where the TestDataProvider class was.

  • Answer # 1

    Is the following execution thread different?

    let realm = try! Realm ()
    let text = realm.objects (cData.self)
      

    From Xcode-Documentation
      optional func session (_ session: WCSession, didReceive file: WCSessionFile)
      Discussion
      This method is called on a background thread of your app.
      (Google Translate)
      This method is called on the app background thread.

  • Answer # 2

    The function to get realm data of watchOS program has been modified as follows.

    // Function to get realm data
    func session (_ session: WCSession, didReceive file: WCSessionFile)
    {
        var config = Realm.Configuration ()
        // --- correction part ↓ ---
        let paths = FileManager.default.urls (for: .documentDirectory, in: .userDomainMask)
        let documentsDirectory = paths [0]
        let realmURL = documentsDirectory.appendingPathComponent ("data.realm")
        try! FileManager.default.copyItem (at: file.fileURL, to: realmURL)
        config.fileURL = realmURL
        // --- Correction ↑ ---
        Realm.Configuration.defaultConfiguration = config
        let realm = try! Realm ()
        let text = realm.objects (cData.self)
        print ("memo: \ (text [0] .memo)")
        print ("name: \ (text [0] .name)")
        }

    I referred this site.
    Files transferred with Watch Connectivity are temporarily stored in a special directory managed by the system. There, they are not allowed to create management files that Realm needs, so if they are not read-only, The file cannot be opened. You must copy the transferred file to a writable location such as the Document directory before opening it.