I have to declare realm string property for to save the value get from API, but the issue is, I don't know which type of data will come from the server.
Sometimes I am getting String value and sometime Int.
Now how I will save data to the realm.
class Fields: Object {
#objc dynamic var default_value: String? = nil
}
API Response
{
access = 1;
default_value = " ";
},
{
access = 1;
default_value = 20;
}
This is the safest (where stringOrInt is the value you're receiving from the API):
fieldsObject.default_value = stringOrInt as? String
But you can also use string interpolation and inject the value directly into a string literal:
fieldsObject.default_value = "\(stringOrInt)"
You can try this solution
1- Relam object class
class Fields: Object {
#objc dynamic private var default_value: String? = nil
#objc var defaultValue: Any?{
didSet{
self.default_value = "\(defaultValue!)"
}
}
open override class func ignoredProperties()->[String] {
return ["defaultValue"]
}
}
1- Test add object in you'r DB
let obj = Fields()
obj.defaultValue = "ahmad"
let obj2 = Fields()
obj2.defaultValue = 1
let realm = try! Realm()
try! realm.write {
realm.add([obj,obj2])
}
3- Result
Related
The function to use a set of Realm objects is always random.
Primary keys must not be changed and they must be unique.
So I added another variable for compare.
And I override isEqual(:) function.
See below my code.
class Model: Object {
#objc dynamic var key = ""
#objc dynamic var id = ""
override static func primaryKey() -> String? {
return "key"
}
override func isEqual(_ object: Any?) -> Bool {
if let object = object as? Model {
return id == object.id
} else {
return false
}
}
}
let model1 = Model()
model1.key = UUID().uuidString
model1.id = "hi"
let model2 = Model()
model2.key = UUID().uuidString
model2.id = "hi"
let model1Array = [model1]
let model2Array = [model2]
let set1 = Set(model1Array)
let set2 = Set(model2Array)
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // [Model { key = 9E814B97-D0CC-4550-BF7B-19645C1DB746; id = hi; }]
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // []
let result = set1.intersection(set2)
print(result) // [Model { key = 8A399388-1FA2-4699-8258-5DA5DFCEC203; id = hi; }]
Every time I run, the values come out randomly.
What did I do wrong?
For Set to work correctly, your objects need to have a correct implementation of Hashable. The Realm Object already implements Hashable, and presumably, the == implementation calls isEqual.
However, the hash should be consistent with isEqual as well, but you haven't overridden hash yet. You should implement hash such that two equal objects (as determined by isEqual) have equal hashes.
One way is to do it like this:
override var hash: Int {
return id.hash
}
I am getting JSON data from server by api call in swift application.
So, I want to store that into Realm data base and again need to fetch to show in tableview.
I have no idea about Realm database, After, checked few forums, I got basic idea for creating Object class.
So, I have installed Realm pod file and imported that library to my classes.
My JSON data is
[{
"type": "story",
"story":
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Trending”,
"story":
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Technology”,
"story":
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
},
{
"type": “Top”,
"story":
{
"author-name": "",
"headline": "Quotes ",
"summary": "Best quotes of Muhammad Ali",
"hero-image": "https://image”
}
}
]
And I have each type keyword has different model class saved data from api data to show in Tableview
like
let storyObj = StoryModule()
let trending = StoryModule()
let technology = StoryModule()
let stotopryObj1 = StoryModule()
and I am saving each key value for every type
if abc.type == "story" {
let storyObj = abc.story
storyObj.authorname = storyObj?.authorname
storyObj.heroimage = storyObj?.heroimage
storyObj.headline = storyObj?.headline
storyObj.summary = storyObj?.summary
self.treningStoriesList.append(storyObj)
}
It is same for remaining Trending, Top and Technology objects.
and the Realm module is
import RealmSwift
class DemoInfo: Object {
#objc dynamic var category = ""
let items = List<DemoList>()
}
class DemoList : Object {
#objc dynamic var authorName = ""
#objc dynamic var imageUrl = ""
#objc dynamic var summary = ""
#objc dynamic var headLine = ""
}
And In MainViewController class,
let realmDB = try! Realm()
But, Here I got struck, How to save those storyObj,technology,top, etc module data and fetch.
Can anyone suggest me?
If you want to add a realm object in your db, you must define a primary key for each realm object classes. So, you need to change your JSON file, after you can create your realm objects like this;
DemoObject.swift
import RealmSwift
class DemoObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var type: String = ""
#objc dynamic var subObject: SubObject?
override static func primaryKey() -> String? {
return "id"
}
}
SubObject.swift
import RealmSwift
class SubObject: Object {
#objc dynamic var id: String = ""
#objc dynamic var authorName: String = ""
#objc dynamic var imageUrl: String = ""
#objc dynamic var summary: String = ""
#objc dynamic var headLine: String = ""
override static func primaryKey() -> String? {
return "id"
}
}
Then, you can use these codes to add your db.
let realm = try! Realm()
let demo = DemoObject()
demo.id = "1"
let sub = SubObject()
sub.id = "1"
sub.authorName = "Author Name"
sub.headLine = "Head Line"
sub.summary = "image Url"
demo.subObject = sub
try! realm.write {
realm.add(demo, update: true)
}
I am getting error as below
Invalid property name , reason: 'Property 'IsRecordDeleted' not found in object of type 'MyCustomModel'
Where as my Model is as Under
#objcMembers public class MyCustomModel : Object {
dynamic var Id : String = ""
dynamic var ProductId : String? = ""
dynamic var IsRecordDeleted : Bool? = false
dynamic var ProductBarcode : String? = ""
override public class func primaryKey() -> String? {
return "Id"
}
}
and I am making query like this :
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self).filter("IsRecordDeleted = false")
What could be problem here. I do not know why my app is crashing with the same error. But If I change the value like
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self).filter("ProductId = 0")
The app gets run, but crashed on when I use IsRecordDeleted in predicate.
Please tell me what could be problem
You can try
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter { $0.IsRecordDeleted == false }
and
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter { $0.ProductId == "0" }
For both
let mSavedItems = mDbHelper.realmObj.objects(MyCustomModel.self)
let filtered = mSavedItems.filter {
$0.IsRecordDeleted == false
&& $0.ProductId == "0"
}
//
let resultPredicate = NSPredicate(format: "ProductId == '0' AND IsRecordDeleted == false")
let filtered = mSavedItems.filter(resultPredicate)
I think you'll find that simply switching to filter blocks instead of string predicates might stop the crash, but will not produce the expected results.
This is because IsRecordDeleted never gets saved to the database. It is not a type that can be represented in Objective-C, therefore it cannot be dynamic, so Realm ignores it.
Take as an example the following class:
#objcMembers class MyObject: Object {
dynamic var id = ""
dynamic var testBool: Bool? = false
override static func primaryKey() -> String {
return "id"
}
}
And say we initialize them like this:
let obj1 = MyObject()
obj1.id = "1"
obj1.testBool = true
let obj2 = MyObject()
obj2.id = "2"
obj2.testBool = false
let realm = try? Realm()
try? realm?.write {
realm?.add(obj1, update: true)
realm?.add(obj2, update: true)
}
If we query Realm for these objects using realm.objects(MyObject.self), you'll get something like this
Results<MyObject> <0x7fe410c0ad90> (
[0] MyObject {
id = 1;
},
[1] MyObject {
id = 2;
}
)
And you'll see that in the database, there indeed is no property named testBool, which was our optional Bool.
You can easily see that the optional Bool may cause problems if you write it out like this instead:
class MyObject: Object {
#objc dynamic var id = ""
#objc dynamic var testBool: Bool? = false // This line will not compile.
override static func primaryKey() -> String {
return "id"
}
}
I'm curious why the IsRecordDeleted needs to be optional in the first place, since it seems to have a value from the get-go. If it doesn't, then something like this will work as expected:
#objcMembers public class MyCustomModel: Object {
dynamic var Id: String = ""
dynamic var ProductId: String? = ""
dynamic var IsRecordDeleted: Bool = false
dynamic var ProductBarcode: String? = ""
override public class func primaryKey() -> String? {
return "Id"
}
}
and you can query via string like you were trying to do in the first place.
If it has to be optional, then Realm provides a RealmOptional for this exact case, that you can look into here.
I am using ObjectMapper to parse JSON objects into Realm.
My class Trip looks like this:
class Trip: Object, Mappable {
dynamic var Id : String? = nil
dynamic var CreatedOn : String? = nil
dynamic var LastModified : String? = nil
required convenience init?(_ map: Map) {
self.init()
}
func mapping(map: Map) {
Id <- map["Id"];
CreatedOn <- map["CreatedOn"];
LastModified <- map["LastModified"];
}
}
I am calling a web service request using Alamofire:
Alamofire.request(.GET, path, headers: ["Token" : auth_token]).responseJSON { response in
let dict : NSDictionary? = response.result.value as? NSDictionary
let test = Mapper<Trip>().map(dict!)
let realm = try! Realm()
realm.beginWrite()
realm.add(test!)
try! realm.commitWrite()
let alltrips : Results<Trip> = realm.objects(Trip)
let firstTrip = alltrips.first
}
In the above code, when I print test, I get:
(AwesomeApp.Trip?) test = 0x0000000154e8f0d0 {
RealmSwift.Object = {
Realm.RLMObjectBase = {
ObjectiveC.NSObject = {}
}
}
Id = "47d86d34-b6f2-4a9f-9e31-30c81a915492"
CreatedOn = "2016-01-20T23:39:41.995Z"
LastModified = "2016-01-20T23:44:39.363Z"
}
When I print, firstTrip, I get
(AwesomeApp.Trip?) firstTrip = 0x0000000154f1f370 {
RealmSwift.Object = {
Realm.RLMObjectBase = {
ObjectiveC.NSObject = {}
}
}
Id = nil
CreatedOn = nil
LastModified = nil
}
I used the Realm Browser and it looks like the values have been written to the database correctly. However, reading the values returns a trip object with all nil values. Why is this ?
EDIT: I printed allTrips using print (allTrips) and this printed out:
Results<Trip> (
[0] Trip {
Id = 47d86d34-b6f2-4a9f-9e31-30c81a915492;
CreatedOn = 2016-01-20T23:39:41.995Z;
LastModified = 2016-01-20T23:44:39.363Z;
}
)
The instance variables of a Realm Object subclass are only used for objects that have not yet been added to a Realm. After an object has been added to a Realm, or for an object that was retrieved from a Realm, the objects getters and setters access data directly from the Realm without the use of the instance variables. This is why the instance variables do not have the values you expect.
With Swift is it possible to create a dictionary of [String:[Object]] from an array of objects [Object] using a property of those objects as the String key for the dictionary using swift's "map"?
class Contact:NSObject {
var id:String = ""
var name:String = ""
var phone:String = ""
init(id:String, name:String, phone:String){
self.id = id
self.name = name
self.phone = phone
}
}
var contactsArray:[Contact]
var contactsDict:[String:Contact]
contactsDict = (contactsArray as Array).map { ...WHAT GOES HERE... }
Let's say you want to use id as the key for the dictionary:
var contactsArray = [Contact]()
// add to contactsArray
var contactsDict = [String: Contact]()
contactsArray.forEach {
contactsDict[$0.id] = $0
}
The difference between map and forEach is that map returns an array. forEach doesn't return anything.
You can achieve this via reduce in a one-line functional-style code:
let contactsDict = contactsArray.reduce([String:Contact]()) { var d = $0; d[$1.id] = $1; return d; }
This also keeps contactsDict immutable, which is the preferred way to handle variables in Swift.
Or, if you want to get fancy, you can overload the + operator for dictionaries, and make use of that:
func +<K,V>(lhs: [K:V], rhs: Contact) -> [K:V] {
var result = lhs
result[rhs.0] = rhs.1
return result
}
let contactsDict = contacts.reduce([String:Contact]()) { $0 + ($1.id, $1) }
Swift 4
There's now a direct way to do this:
https://developer.apple.com/documentation/swift/dictionary/3127163-init
It's an initializer for Dictionary that lets you return a string key for each element in a Collection that specifies how it should be grouped in the resulting Dictionary.