I'm getting started with realm and trying to figure out the best way to write my model layer, so after overthinking about it I decide to ask here to get some opinions. Here we go:
I'm writing a realm version of these tables:
Account
id - String (PK)
Name - String
Type - Int
Checking Account
id - String (FK PK)
In this case a Checking Account is an Account, but realm still not support inheritance (I think using Account as a superclass would be the better way to figure these tables out in the model layer)
This is what I actually did with realm:
Account class:
import Foundation
import RealmSwift
class Account: Object {
dynamic var id = NSUUID().UUIDString
dynamic var name = ""
dynamic var type = 3
override static func primaryKey() -> String {
return "id"
}
}
Checking Account class:
import Foundation
import RealmSwift
class CheckingAccount: Object {
dynamic lazy var id: String = {
return self.account.id
}()
dynamic var account = Account()
convenience init(name: String, type: AccountType) {
self.init()
self.account.name = name
self.account.type = type.rawValue
}
override static func primaryKey() -> String? {
return "id"
}
}
What about it? It's a "Don't do" way to figure out my SQL tables with realm?
Thank you!
Related
I am using Apollo for Swift in an iOS app. I have multiple types that all represent the same object. These types are auto-generated from a schema file and look something like this.
struct CurrentUser {
var id: String
...
}
struct MyUser {
var id: String
...
}
Basically Apollo generates multiple Swift types (one for each query) for the same underlying data type.
I want to create a new struct that unifies these types.
I would like to do something like this:
protocol UserProtocol {
var id: String { get }
}
struct User {
var id: String
...
init(_ data: UserProtocol) {
self.id = data.id
...
}
}
This approach however gives me an error when I try to construct a user object, telling me that "Type MyUser does not conform to UserProtocol". If I try to coerce the type with data as! UserProtocol I get a crash.
The only solution I've found is the following:
enum UserType {
case .currentUser(CurrentUser)
case .myUser(MyUser)
}
struct User {
var id: String
...
init(_ data: UserType) {
switch data {
case .myUser(let user):
self.id = data.id
...
case .currentUser(let user):
self.id = data.id
...
}
}
}
This approach works, but it leads to a lot of duplicated code in the init function. Is there a better way to do this in Swift?
I suspect the problem is that you need to explicitly conform the Apollo generated types to your protocol:
extension CurrentUser: UserProtocol { }
extension MyUser: UserProtocol { }
Remember that Swift is not duck-typed like some other languages, so a type with member var id: String is not UserProtocol until you declare it as such.
If for some reason you need to do some transformation of the Apollo types to fit the app models in the future, those extensions are a good place to do that, too.
I have a question regarding my architecture of multiple Realms in my project. Consider the following model:
#objcMembers class Book: Object {
dynamic var bookID = UUID().uuidString
dynamic var title: String = ""
dynamic var year: Int = 0
override static func primaryKey() -> String {
return "bookID"
}
}
What I would like to do is to be able to either like a book or to put it into a shopping list.
The first solution I came up with was to have three default Realms for:
Books - RealmBooks
Books liked - RealmLiked
Books added to a shopping list - RealmShopping
With this fairly simple approach I was forced to have several Realms. In the future I would like to sync the data from the above Realms to the Realm Cloud. So to avoid this is it possible to have an architecture that combines the data of let's say RealmLiked and RealmShopping? This could be of an object type UserSettings:
#objcMembers class UserSettings: Object {
dynamic var userID = UUID().uuidString
let likedBooks = List<Book>()
let shoppingListBooks = List<Book>()
override static func primaryKey() -> String {
return "userID"
}
}
Then I would simply sync UserSettings and this would act like the master Realm. Obviously the remaining RealmBooks would be synced in a separate Realm. The reasons for all of this is due to trying to keep my project simple as well as the limitation of having Up to 3 Realm Instances synced in the standard version of Realm Platform Cloud.
I would like to know the best practice in this scenario. Any help is much appreciated.
I'm trying to retrieve data from an online data storage using the func that I found online on the official Backendless docs! but when I try to use persona like a Lista(my own class) Object, I get the error: Could not cast value of type '__NSDictionaryM' (0x10c1ccfc0) to 'InLIsta_.Lista' (0x108439790).
I search over this site but the answer aren't specific for the Backendless case, so I hope that anyone can help me
this is my code (obviously I've declared all the var and let necessary to the code to run):
class Lista : NSObject {
var nome: String?
var pr: String?
var pagamento = 0
var entrato: Bool = false
var commenti: String?
var objectId: String?
var created: NSDate?
var updated: NSDate?
}
func findQ() {
Types.tryblock({ () -> Void in
let startTime = NSDate()
let found = self.backendless.persistenceService.of(Lista.ofClass()).find(self.query)
let currentPage = found.getCurrentPage()
print("Loaded \(currentPage.count) name objects")
print("Total name in the Backendless storage - \(found.totalObjects)")
for person in currentPage {
let persona = person as! Lista // here i get error
print("Restaurant <\(Lista.ofClass())> name = \(persona.nome)")
self.nomi.append(persona.nome!)
}
print("Total time (ms) - \(1000*NSDate().timeIntervalSinceDate(startTime))")
},
catchblock: { (exception) -> Void in
print("Server reported an error: \(exception as! Fault)")
}
)
}
The backendless persistence service has a method -(void)mapTableToClass:(NSString *)tableName type:(Class)type; that you need to call for each of your custom classes so they'll be used during the deserialisation.
self.backendless.persistenceService.mapTableToClass("Lista", type: Lista.self)
This needs to be done before any calls are made to use the persistence service.
Note that the classes, if not defined in obj-c, must be exported to obj-c. Note that this also means you can't have any optionals.
Ideally you should use the platform code generation to create your model class definitions to ensure all of the attributes are created with the appropriate types. A failure to map to your custom class could be caused by type mismatches or name mismatches. Optionals will always fail in the current SDK implementation.
For example:
class User: Object {
dynamic var name: String = "Thor"
dynamic var profile: Profile?
}
class Profile: Object {
dynamic var id: Int = 0
override static func primaryKey() -> String {
return "id"
}
}
So, I want Realm to not create a new user when the profile is an update using the profile's primaryKey.
In code,
let json = JSON(value)
let realm = try! Realm()
try! realm.write {
let user = User(json: json)
realm.add(user, update: true)
}
Since User does not have a primaryKey, it will create a new user every time. However, since Profile does have a primaryKey, it only creates one profile. All the users points to that same one profile. What I would like is for the User to use the primary key on the Profile and only create a new User when a new Profile is created.
Any ideas?
Thanks.
What you're asking for amounts to giving the User class a concept of identity, which in Realm is represented by primary keys.
I'd recommend that you use the same primary key to represent both a User and their associated Profile. Alternatively, if these models can only exist together in a one-to-one relationship, why not just combine them?
class User: Object {
dynamic var id: Int = 0
dynamic var name: String = "Thor"
override static func primaryKey() -> String {
return "id"
}
}
I'm assuming you have more properties in your Profile model.
I have code that saves an RLMObject subclass to the realm database. This code works and I have used the realm browser to verify that it is saved as expected.
I then want to query the realm database for this object that I saved, and I want to cast it to the RLMObject subclass that is was before I saved it.
Here is the code:
let queryResults = RealmSubclass.allObjects()
for result in queryResults {
if result is RealmSubclass {
let temp = result as RealmSubclass
println(temp.name)
println(temp.dateOfBirth)
println(temp.gender)
}
}
When I check the values in the debug console, using print object, I see values that I expect. However, when I do a type cast to RealmSubclass the resulting object has no correct values, only nil values.
Why could this be? I have read the documentation, to no avail.
EDIT:
Here is the RLMObject subclass:
public class RealmSubclass: RLMObject {
public dynamic var id: String = NSUUID().UUIDString
public dynamic var name: String = ""
public dynamic var dateOfBirth: NSDate = NSDate()
public dynamic var gender: NSString = Consts.Gender.Male
override public class func primaryKey() -> String {
return "id"
}
}
Ok, it seems that the values were actually being returned. What happened is that Swift debugging is not up to standard yet. The debug area was showing incorrect information.