I'm having a problem in fetching a single row in a table. My problem is that I cannot display it. Here is what I have so far
let feed: RLMObject = FeedsModel.objectsWhere("id = 1").firstObject()!
print(feed.title)
Thank you very much!
You should fetch the single object with primary key like this:
let realm = try! Realm()
let feeds = realm.objectForPrimaryKey(FeedsModel.self, key: "1")
You're attempting to access the title property of RLMObject, which doesn't exist. This property only exists on FeedsModel. Instead, you should cast the object as a FeedsModel:
let feed = FeedsModel.objectsWhere("id = 1").firstObject() as! FeedsModel
print(feed.title)
If you'd like to use Realm from Swift with nicer generics, I'd encourage you to consider using Realm Swift instead of Realm Objective-C.
Related
I have realm object which is in objective-c class (our project is mix&match between swift and objective-c)
I know that I can access
[ClassName objectForPrimaryKey:] in objc
but I don't know how can I use this method in swift file?
is this possible?
Thanks.
In case of Swift you should use the following code:
let realm = try! Realm()
let object = realm.object(ofType: ClassName.self, forPrimaryKey: primaryKey)
In case if you are using Realm as an Objective-C library in Swift, then:
let object = ClassName(forPrimaryKey: primaryKey)
I'll make it short as possible.
I have an API request that I fetch data from (i.e. Parse).
When I'm getting the results I'm writing it to Realm and then adding them to a UICollectionView's data source.
There are requests that take a bit more time, which run asynchronous. I'm getting the needed results after the data source and collection view was already reloaded.
I'm writing the needed update from the results to my Realm database.
I have read that it's possible to use Realm's Results. But I honestly didn't understood it. I guess there is a dynamic and safe way working with collection views and Realm. Here is my approach for now.
This is how I populate the collection view's data source at the moment:
Declaration
var dataSource = [Realm_item]()
where Realm_item is a Realm Object type.
Looping and Writing
override func viewDidLoad() {
super.viewDidLoad()
for nowResult in FetchedResultsFromAPI
{
let item = Realm_item()
item.item_Title = nowResult["Title"] as! String
item.item_Price = nowResult["Price"] as! String
// Example - Will write it later after the collectionView Done - Async request
GetFileFromImageAndThanWriteRealm(x.image)
// Example - Will write it later after the collectionView Done - Async request
dataSource.append(item)
}
//After finish running over the results *Before writing the image data*
try! self.realm.write {
self.realm.add(self.dataSource)
}
myCollectionView.reloadData()
}
After I write the image to Realm to an already created "object". Will the same Realm Object (with the same primary key) automatically update over in the data source?
What is the right way to update the object from the data source after I wrote the update to same object from the Realm DB?
Update
Model class
class Realm_item: Object {
dynamic var item_ID : String!
dynamic var item_Title : String!
dynamic var item_Price : String!
dynamic var imgPath : String?
override class func primaryKey() -> String {
return "item_ID"
}
}
First I'm checking whether the "object id" exists in the Realm. If it does, I fetch the object from Realm and append it to the data source. If it doesn't exist, I create a new Realm object, write it and than appending it.
Fetching the data from Parse
This happens in the viewDidLoad method and prepares the data source:
var query = PFQuery(className:"Realm_item")
query.limit = 100
query.findObjectsInBackgroundWithBlock { (respond, error) -> Void in
if error == nil
{
for x in respond!
{
if let FetchedItem = self.realm.objectForPrimaryKey(Realm_item.self, key: x.objectId!)
{
self.dataSource.append(FetchedItem)
}
else
{
let item = Realm_item()
item.item_ID = x.objectId
item.item_Title = x["Title"] as! String
item.item_Price = x["Price"] as! String
let file = x["Images"] as! PFFile
RealmHelper().getAndSaveImageFromPFFile(file, named: x.objectId!)
self.dataSource.append(item)
}
}
try! self.realm.write {
self.realm.add(self.dataSource)
}
self.myCollectionView.reloadData()
print(respond?.count)
}
}
Thank you!
You seem to have a few questions and problems here, so I'll do my best.
I suggest you use the Results type as your data source, something like:
var dataSource: Results<Realm_item>?
Then, in your viewDidLoad():
dataSource = realm.objects(Realm_item).
Be sure to use the relevant error checking before using dataSource. We use an optional Results<Realm_item> because the Realm object you're using it from needs to be initialised first. I.e., you'll get something like "Instance member * cannot be used on type *" if you try declaring the results like let dataSource = realm.objects(Realm_item).
The Realm documentation (a very well-written and useful reference to have when you're using Realm as beginner like myself), has this to say about Results...
Results are live, auto-updating views into the underlying data, which means results never have to be re-fetched. Modifying objects that affect the query will be reflected in the results immediately.
Your mileage may vary depending on how you have everything set up. You could try posting your Realm models and Parse-related code for review and comment.
Your last question:
What is the right way to update the "object" from the Data Source after i wrote the update to same object from the Realm DB?
I gather you're asking the best way to update your UI (CollectionView) when the underlying data has been updated? If so...
You can subscribe to Realm notifications to know when Realm data is updated, indicating when your app’s UI should be refreshed for example, without having to re-fetch your Results.
Please, tell me, how to rearrange items of Realm's list of objects by index? I.e. I'm looking something like
let movingElement = array[oldIndex]
array.removeAtIndex(oldIndex)
array.insert(movingElement, atIndex: newIndex)
if it was with a casual Swift array of something.
But for List in Realm I can not do the same thing:
let realm = try! Realm()
var all = try! Realm().objects(element)
realm.write {
all.removeAtIndex() // all of type
Another option is to
let realm = try! Realm()
let element = try! Realm().objects(Element)[oldIndex]
realm.write{
realm.delete(element)
realm.add(...) // How to set index to place new object at?
}
But how to insert element in proper place? May be there is a proper method how to move elements of realm of the same type (class) by index?
Thanks in advance!
You cannot do it with query results, as they are unordered (or in a specific order if you sort them). But if you put them into Realm List (which you can store as member in a Realm object), then you can use both move and swap methods to reorder elements.
Here is the API docs for the the List type: https://realm.io/docs/swift/latest/api/Classes/List.html
I am trying to use Realm for my iOS app. When updating the local Realm DB using createOrUpate, it rewrites the unprovided properties with default values, rather than keep them unchanged. The Realm I use is up to date, 0.93. Anybody has the same issue?
let realm = RLMRealm.defaultRealm()
realm.beginWriteTransaction()
for matchedUser in matchedUsers {
let newMatchedUser = MatchedUser()
newMatchedUser.objectId = matchedUser.objectId
newMatchedUser.username = matchedUser.username
newMatchedUser.email = matchedUser.email
newMatchedUser.fullname = matchedUser["fullname"] as! String
//they are other properties unprovided here.
MatchedUser.createOrUpdateInDefaultRealmWithValue(newMatchedUser)
}
realm.commitWriteTransaction()
So, I figured out what the issue was. It turns out you cannot user newMachtedUser to update the DB because it will initialize it first and the default values will be provided for this initialization process. The right way is to using individual values to update, or create an dictionary/array for that update.
I am new to iOS development using Swift language.
I am using CoreData in my app as a database option.
I am using NSFetchRequest for fetching records from the table. I can retrieve all records from the table, but I can't retrieve a specific row from the same table.
I have checked for the solutions online and other forums, but I am unable to get a proper solution for this.
I want to implement this in Swift only. I don't want to add the sqlite library or Bridging-wrapper (Objective - C) which will be my last option to implement this.
Any links or tutorials or suggestions will be helpful.
NSFetchRequest also support NSPredicate. With NSPredicate you can choose which exactly rows or row you need from Core Data.
More about NSPredicate - https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSPredicate_Class/
You can fetch a desired row by executing a fetch request, casting it as an array, and simply using subscript to retrieve an index. Or you can narrow down your results using a unique id and a predicate and getting the object at index 0.
if let results = managedObjectContext?.executeFetchRequest(fetchRequest, error: nil) as? [SomeClass] {
let someObject = results[someIndex]
}
As Pavel said, use NSPredicate. Here is a working example from my code, it might help you to get started ;) I added some comments below relevant lines
var req = NSFetchRequest(entityName: "YourDBTable")
// your db-table goes here
req.sortDescriptors = [NSSortDescriptor(key: "timeMillis", ascending: true)]
// if you want to sort the results
let start = NSNumber(longLong:int64StartValue)
// you need to convert your numbers to NSNumber
let end = NSNumber(longLong:int64EndValue)
let pred = NSPredicate(format:"timeMillis>=%# AND timeMillis <=%# AND foreignTableObject=%#",start,end, foreignTableObject)
// if you have relationships, you can even add another NSManagedObject
// from another table as filter (I am doing this with foreignTableObject here)
req.predicate = pred
var fetchedResults = managedContext?.executeFetchRequest(req,error: &error) as! [YourDBTable]?
// YourDBTable-class was created using the Xcode data model -> Editor -> Create NSManagedObject SubClass... - option
if let results = fetchedResults {
// iterate through your results
}