Can't get Sync working

cloud

#1

Hello here

I’m new in Realm. Usually, I don’t write such posts as tending to solve problems myself. This time I lost too much time to proceed. It’s all started from “Reactive Programming with Swift” book where I was inspired by Realm and how it plays with RxSwift. I decided to write my own app and use it instead Firebase (proven to be working yet challenging for real-world apps).

After passing tutorials I have implemented the authentication suite: - login, -signup, -email confirmation (with custom server) and stucked!

What happens?
Everyhing works fine, however once I re-launch the app - I’m being logged out and no data in Realm.
I tried different approaches and nothing works.

  1. Configuration from tutorials, cloud sync:
let realm = try Realm(configuration: SyncUser.current!.configuration())

As far as I understand, such configuration allows data to be synced and relative to SyncUser
After app reload - no data, user is logged out (I’m running up on real device)
I can log in back but no data at specific endpoint

I use helper function

fileprivate func withRealm<T>(_ operation: String, action: (Realm) throws -> T) -> T? {
    do {
      let realm = try Realm()
      return try action(realm)
    } catch let err {
      print("Failed \(operation) realm with error: \(err)")
      return nil
    }
  }

and then call it here:

func currentViewer() -> Observable<UserItem> {
    guard let identity = SyncUser.current?.identity else { return .empty() }

    let result = withRealm("getting current viewer") { realm -> Observable<UserItem> in
      let users = realm.objects(UserItem.self).filter("owner == %@", identity)
      
      print(users)

      guard let user = users.first else { return .empty() }

      return Observable.just(user)
    }

    return result ?? .empty()
  }

and UserItem:


import Foundation
import RealmSwift
import RxDataSources

class UserItem: Object {
  @objc dynamic var uid: Int = 0
  @objc dynamic var owner: String = ""
  @objc dynamic var email: String = ""
  @objc dynamic var added: Date = Date()
  
  override class func primaryKey() -> String? {
    return "uid"
  }
}

extension UserItem: IdentifiableType {
  var identity: Int  {
    return self.isInvalidated ? 0 : uid
  }
}

the result of the call

Results<UserItem> <0x10640a170> (

)

However, I can see data in RealmStudio on default realm

  1. Default?
let realm = try Realm()

it’s clear that it is local-oriented Realm. Everything works just fine.
App reload, guess what?
Log out. Of course :slight_smile:

So I’ve tried also fullSync with specifying REALM_URL from Constants nothing works.
I’m definitely doing something wrong but can’t find a real case example or answer.
Honestly speaking - TODO apps just wrong. I’d either offer Full Authentication example with shared ToDo items with Users - this would cover the understanding of how it works in a case close to real world.

What I’m doing wrong?


#2

There’s quite a bit of code there so to me at least, the actual issue is a bit unclear. I think you have a couple of different issues going on so let me shotgun this as maybe it will help.

My guess is the main problem is your missing the subscribe right after your realm.objects call

let userItemResults = realm.objects(UserItem.self)
let userItemSubscription = self.userItemResults.subscribe()

One of the issues you may be running into is that the Realm Documentation is outdated and doesn’t always match the current API so while it’s a good starting point, you’ll often have to experiment with it to get the right calls in the right order. Don’t be shy about opening a ticket with support.

Here’s a function we use to authenticate a user. This will handle when a user is already authenticated of if they need to authenticate.

func handleLogIn() {
    if let _ = SyncUser.current {
        print("user already logged in")
    } else {
        let creds = SyncCredentials.nickname("Jay", isAdmin: true)
        SyncUser.logIn(with: creds, server: Constants.AUTH_URL) { user, err in
            if let _ = user {
                print("logged in")
            } else {
                print("failed to log in")
            }
        }
    }
}

We have a static file that holds our connection constants, which is pulled from the documentation

struct Constants {
    static let MY_INSTANCE_ADDRESS = "your_app.cloud.realm.io" // <- update this
    static let AUTH_URL  = URL(string: "https://\(MY_INSTANCE_ADDRESS)")!
    static let REALM_URL = URL(string: "realms://\(MY_INSTANCE_ADDRESS)/your_realm")!
}

Lastly we have a single RealmService connection that, whenever we need to talk to realm we call it.

import RealmSwift
var RealmService = ReferenceRealm.shared.realm

private class ReferenceRealm {
    static let shared = ReferenceRealm()
    
    lazy var realm: Realm = {
        let syncUserConfig = SyncUser.current?.configuration(realmURL: Constants.REALM_URL, 
                                      fullSynchronization: false, 
                                      enableSSLValidation: true)
        let realm = try! Realm(configuration: syncUserConfig!)
        return realm
    }()
}

and then finally, if you want to read data from ROS here’s a snippet

let realm = RealmService
let userItemResults = realm.objects(UserItem.self)
let userItemSubscription = self.userItemResults.subscribe() //got to have this or else you'll get no results
for userItem in userItemResults {
   print(userItem.owner)
}

#3

Thank you for quick feedback!
Regarding .subscribe call I believe is handled by RxRealm.

I haven’t provided the example of how I call for it… sorry

service.currentViewer().flatMap { user in
       //here flatMap works like subscribe projecting each value
       //then I pass it to another function which creates an Observable (handled by RxSwift,  similar to what Realm .objects method does)
        return service.isEmailConfirmed(user: user)
      }
      .subscribe(onNext: { confirmed in


        if confirmed {
          DispatchQueue.main.async {
            let homeViewModel = HomeViewModel(
              viewerService: service,
              coordinator: sceneCoordinator
            )
            
            sceneCoordinator.transition(to: Scene.home(homeViewModel), type: .root)
          }
          
        }
      })
      .disposed(by: disposeBag)

I just bought a book “Moden Swift Apps with Realm” to fill the gaps.


#4

Lost another day. Book doesn’t help. last chapter dedicated for Realm Platform doesn’t work
Overall looks promising but just feels broken. Wasted the whole week in total, super frustrating :frowning: And they want $30/mo with non-working product :\ Documentation isn’t helpful as well.
Technology looks promising and I think just offline Database is cool, but Real Platform all this Sync story is just awful experience :cry:

Hope I can return one day and take it back, for now - I’m done. Can’t understand how people can build collaborative apps if simple functions doesn’t work