The problem i have is very strange. I query this table:
with this class:
class ParseFriend: PFObject, PFSubclassing {
override class func load() {
self.registerSubclass()
}
class func parseClassName() -> String! {
return "Friend"
}
#NSManaged var fromUser: ParseUser!
#NSManaged var toUser: ParseUser!
#NSManaged var status: NSNumber!
}
And here where i create the request:
let fromQuery = ParseFriend.query()
fromQuery.whereKey("toUser", equalTo: ParseUser.currentUser())
fromQuery.includeKey("fromUser")
let toQuery = ParseFriend.query()
toQuery.whereKey("fromUser", equalTo: ParseUser.currentUser())
toQuery.includeKey("toUser")
let orQuery = PFQuery.orQueryWithSubqueries([fromQuery, toQuery])
orQuery.findObjectsInBackgroundWithBlock { (results, error) -> Void in
println("this is never called")
}
For some reason "this is never called" only gets executed if i remove "includeKey" from both queries and works as expected. Any ideas? I get no error, just jumps the completion block.
I notice if i put a randomly key in includeKey i get the same scenario. And those users exists in the User table.
Use includeKey in the orQuery instead of individual PFQuerys
Related
I am using Realm notification block for updating messages in a page.
let messageResult = realm.Object(MessageRealm.self)
notificationTokenMessage = messageResult.addNotificationBlock{ [weak self] (changes: RealmCollectionChange) in {
switch changes {
case .initial(_),
.update(_, _, _, _):
self?.tableView.reloadData()
default:
break
}
}
}
In MessageRealm class, there is a property, name author. An author is basically a UserRealm object.
Class MessageRealm extends Object {
dynamic var _id: String? = nil
dynamic var body: String? = nil
dynamic var author: UserRealm? = nil
override class func primaryKey() -> String? { return "_id" }
}
Class UserRealm extends Object {
dynamic var _id: String? = nil
dynamic var fullName: String? = nil
dynamic var status: String? = nil // 'online' or 'offline'
override class func primaryKey() -> String? { return "_id" }
}
When a new message is received from socket, the message page is updated as it gets notifications from Realm. But, when user update notification is received from socket, the Realm updates the message page. I don't want to update message page for an update in author object.
Probable Solutions:
Class MessageRealm extends Object {
dynamic var _id: String? = nil
dynamic var body: String? = nil
dynamic var author: UserRealm? = LinkingObjects(fromType: UserRealm.self, property: "messages")
override class func primaryKey() -> String? { return "_id" }
}
Class UserRealm extends Object {
dynamic var _id: String? = nil
dynamic var fullName: String? = nil
dynamic var status: String? = nil // 'online' or 'offline'
let messages = List<MessageRealm>()
override class func primaryKey() -> String? { return "_id" }
}
We can solve it using LinkingObjects. But, this inverse relation needs a direct relation to map. Am I right? So, need to have a property of List of Messages in User. And from MessageRealm I have to link to User. But this will be complicated to maintain.
Store author's id in MessageRealm as a foreign key like a traditional database.
What do you suggest?
How can we do normalization in Realm to avoid update issue?
Is there any convention or best practices to manage a bigger database? (I am aware of Tim's answer https://stackoverflow.com/a/31594548/2666902 )
In my opinion, the best solution would be keeping the author property as a one-to-one relationship from MessageRealm to UserRealm, since a single message can only have one author and creating an inverse relationship in UserRealm.
class MessageRealm: Object {
dynamic var _id: String? = nil
dynamic var body: String? = nil
dynamic var author: UserRealm? = nil
override class func primaryKey() -> String? { return "_id" }
}
class UserRealm: Object {
dynamic var _id: String? = nil
dynamic var fullName: String? = nil
let messages = LinkingObjects(fromType: MessageRealm.self, property: "author")
override class func primaryKey() -> String? { return "_id" }
}
This way, you only need to keep the author property of your messages updated and the messages property of UserRealm will automatically keep in sync, so any time you try to access it, you will see all MessageRealm objects, where the author equals the specific user.
I'm using Xcode 6.4 and Swift in iOS 8.4 project
I have a model with one to many relationship
class Account: NSManagedObject {
#NSManaged var userId: Int
#NSManaged var accessToken: String?
#NSManaged var userName: String
#NSManaged var sex: String
#NSManaged var email: String
#NSManaged var avatarUrl: String?
#NSManaged var friends: NSSet
}
class User: NSManagedObject {
#NSManaged var id: Int
#NSManaged var userName: String
#NSManaged var sex: String
#NSManaged var email: String
#NSManaged var avatarUrl: String
}
When I'm trying to remove all friends it doesn't work:
extension Account {
func replaceFriends(friends:[User]) {
var friendsList = self.mutableSetValueForKey("friends")
friendsList.removeAllObjects()
friendsList.addObjectsFromArray(friends)
}
func getFriends() -> [User] {
return self.mutableSetValueForKey("friends").allObjects as! [User]
}
}
class AccountDao: BaseDao {
private class func findAccount() -> Account? {
if let result = moc.executeFetchRequest(NSFetchRequest(entityName: "Account"), error: nil) as? [Account] {
if (!result.isEmpty) {
return result[0]
}
}
return nil
}
class func getAccount() -> Account {
return findAccount() ??
NSEntityDescription.insertNewObjectForEntityForName("Account", inManagedObjectContext: moc) as! Account;
}
}
During saving I'm setting empty array:
class func saveObjectContext() -> Bool {
var error: NSError?
var account = AccountDao.getAccount()
account.replaceFriends([User]())
if !moc.save(&error) {
self.log.error("Error during saving context, \(error)")
return false
} else {
println("Count in log \(AccountDao.getAccount().getFriends().count)")
self.log.info("Info save context \(error)")
return true
}
}
In log it returns 0:
Count in log 0
But in ControllerView still I'm getting AccountDao.getAccount().getFriends().count == 1. Method replaceFriends works only first time when I fetch and save data. And it save changes for simple properties like userName but not for friends. Do you have any ideas?
I found that in relation one to many Account -> User without inverse relationship in User, after changing list in Account every user in list have to be marked that has changed (property updated == true). But it always was set to false.
I added additional property to User, and after every change of list I had to change this property like user.toUpdate = true. After this change everything is working fine.
Below is my code that I am using to query for an object from Parse:
func findEmployeeForLoggedInUser(completion: (array: [AnyObject], error: String?) -> Void) {
var query = PFQuery(className: "Employee")
query.whereKey("employerId", equalTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock { (results, error) -> Void in
println(results)
var employeeArray = results
if let error = error {
let errorString = error.userInfo?["error"] as? String
if let objects = employeeArray {
completion(array: objects, error: errorString)
} else {
completion(array: [], error: errorString)
}
} else {
completion(array: employeeArray!, error: nil)
}
}
}
Below is the code where the subclass of PFObject was declared:
class PFEmployee: PFObject, PFSubclassing {
override class func initialize() {
self.registerSubclass()
}
class func parseClassName() -> String {
return "Employee"
}
#NSManaged var name: String
#NSManaged var jobDesc: String
#NSManaged var numberOfPoints: Int
#NSManaged var education: String
#NSManaged var birthday: String
#NSManaged var employerId: String
#NSManaged var profilePicture: PFFile?
#NSManaged var email: String
#NSManaged var commentary: String
}
My app is crashing, and I suspect it has something to do with this. Am I doing all of this correctly?
Use this crash free code...
var stuffarray = [String]()
var query = PFQuery(className:"ClassName")
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
// The find succeeded.
println("Successfully retrieved \(objects!.count) scores.")
// Do something with the found objects
if let objects = objects as? [PFObject] {
for object in objects {
stuffarray.append(object.valueForKey("Column")! as! String)
}
}
} else {
// Log details of the failure
println("Error: \(error!) \(error!.userInfo!)")
}
dispatch_async(dispatch_get_main_queue()) {
self.alert("\(stuffarray)", Message: "")
}
}
I've been trying to implement Parse in my application and can't seem to get my Subclass to save to the backend. I've been using the guides provided by Parse here and here but still can't get it to work.
My Subclass looks like this:
import Foundation
import Bolts
import Parse
class Fillup : PFObject, PFSubclassing {
#NSManaged var username: String?
#NSManaged var amount: String?
#NSManaged var cost: String?
#NSManaged var date: NSDate?
#NSManaged var location: CLLocation?
override class func initialize() {
var onceToken : dispatch_once_t = 0;
dispatch_once(&onceToken) {
self.registerSubclass()
}
}
static func parseClassName() -> String {
return "Fillup"
}
Accessing the variables works fine using let x = fillup.amount as String!.
However, in my save method the variables always end up being nil.
Here's a small example from my save method:
#IBAction func saveTapped(sender: AnyObject) {
// instantiate new Fillup object
var fillup :Fillup?
//check for nil on variables
if let username = PFUser.currentUser()?.username {
println(username)
fillup?.username = username
}else{
println("Username is nil.")
}
println(fillup?.username)
//save object to backend
fillup?.saveInBackgroundWithBlock({ (success, error) -> Void in
if error != nil {
println("Error: " + error!.localizedDescription)
}else{
println("Fillup saved!")
}
})
}
The output always looks like:
mforrest3
nil
and as the variable is nil it doesn't save successfully to the backend.
I've not included the code for the other variables for simplicity's sake however I think this should still work.
If anyone could point me in the direction of a good guide or help me come up with an answer/reason that would be great.
This line
var fillup :Fillup?
Is not creating a new instance, it's just defining an optional local variable of the appropriate type. You should have
var fillup = Fillup.object()
To actually call the constructor for the class (and allow the compiler to determine the class in this case)
I'm pretty new to iOS/Swift/Parse and I'm trying to build a model of a class using PFSubclassing.
The data I'm trying to represent should look something like this
{
text: ""
location : {
name: "",
longitude: "",
latitude: ""
}
}
So fare the model I'm have is
class LocationModel {
var name: String?
var longitude: Float?
var latitude: Float?
}
class PostModel: PFObject, PFSubclassing {
class func parseClassName() -> String! {
return "Post"
}
#NSManaged var text: String?
var location: LocationModel?
}
The test property is being saved successfully but I'm unable to get the location properties to save.
The code I'm using to save a record to parse is
var test = PostModel()
test.location?.name = "ESB"
test.location?.latitude = 1
test.location?.longitude = 1
test.text = "This is a test post to see if this works!"
test.saveEventually { (success: Bool, error: NSError!) -> Void in
println(error)
println(success)
}
I did a lot of digging online but I'm unable to find a solution on how to represent an Object datatype in Swift using Parse PFSubclassing
Any help would be greatly appreciated.
Thank you
Here's my solution:
I will create a Hero object for example.
class Hero: PFObject, PFSubclassing {
#NSManaged var strengthPoint: Double
#NSManaged var name: String
static func parseClassName() -> String {
return "Hero"
}
init(strengthPoint: Double, name: String) {
super.init()
self.strengthPoint = strengthPoint
self.name = name
}
init(pfObject: PFObject) {
super.init()
self.strengthPoint = pfObject.object(forKey: "strengthPoint") as! Double
self.name = pfObject.object(forKey: "name") as! String
}
override init() {
super.init()
}
override class func query() -> PFQuery<PFObject>? {
let query = PFQuery(className: self.parseClassName())
query.order(byDescending: "createdAt")
query.cachePolicy = .networkOnly
return query
}
}
Now, after defining your model, you can use these methods to store and retrieve
Create your object in server
func createHero() {
let hero = Hero(strengthPoint: 2.5, name: "Superman")
hero.saveInBackground { (isSuccessful, error) in
print(error?.localizedDescription ?? "Success")
}
}
Retrieve object from server
func retrieveHero() {
let query = Hero.query()
query?.getFirstObjectInBackground(block: { (object, error) in
if error != nil {
print(error?.localizedDescription ?? "Something's wrong here")
} else if let object = object {
let hero = Hero(pfObject: object)
print(hero.strengthPoint) // 2.5
print(hero.name) // Superman
}
})
}
I have seen several different methods for PFSubclassing in Swift 1.2, but the following works best for me:
To begin with, make sure that you have the following in your Objective-C Bridging Header:
#import <Parse/PFObject+Subclass.h>
Here is a very basic example of subclassing PFObject:
import Foundation
import Parse
class Car: PFObject, PFSubclassing {
override class func initialize() {
self.registerSubclass()
}
static func parseClassName() -> String {
return "Car"
}
#NSManaged var model: String
#NSManaged var color: String
#NSManaged var yearManufactured: Int
}
So in your case, this would be:
class PostModel: PFObject, PFSubclassing {
override class func initialize() {
self.registerSubclass()
}
static func parseClassName() -> String {
return "Post"
}
#NSManaged var text: String?
}
Concerning your LocationModel...I'm a bit confused as to what exactly you are trying to accomplish with that. I hope this helps.