iOS - Trouble saving subclass to Parse backend - ios

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)

Related

Swift 5: I have a problem when I try to instantiate a viewmodel for testing

I'm trying to instantiate my viewmodel for testing, in this case I don't need its parameters, but as it asks me to add them, when I try I get an error "Constant 'data' used before being initialized"
This is my code:
struct Account: Codable {
let details: [Details]?
}
struct Details: Codable {
let id: String?
let currency: String?
let interest: Float64?
let date: String?
}
class DetailViewModel {
private let data: Details?
init(data: Details) {
self.data = data
}
}
Tests:
class DetailViewModelTest: QuickSpec {
override func spec() {
var viewModel : DetailViewModel!
let data: Details!
viewModel = DetailViewModel(data: data) // I have error in this line
}
}
Is there a way to instantiate my viewmodel without parameters? Or a better way to handle this?
To use Details in a test with hardcoded values you either need to create it from some json or add another init to initialise all values, here I am using the latter. I am adding it in an extension and created a static method that uses the init to create an object with hard coded values.
extension Details {
private init(id: String, currency: String, interest: Float64, date: String) {
self.id = id
self.currency = currency
self.interest = interest
self.date = date
}
static func createStub() -> Details {
Details(id: "1", currency: "EUR", interest: 1.23, date: "2022-02-12")
}
}
This is one way of doing it, the init could be designed in many ways but this is to show you how to move forward.
This can then be used in the test class
class DetailViewModelTest: QuickSpec {
override func spec() {
let viewModel = DetailViewModel(data: Details.createStub())
//...
}
}
you should:
let data: Details = Details() // create your data

Calling setValuesForKeys fails in my Swift 4 code

I'm having this problem, im trying to retrieve data from the firebase database, but it's saying the profilepic isn't a key, but it is. This is the object class.
class User: NSObject {
var firstname: String?
var lastname: String?
var username: String?
var profilepic: String?
}
and this is me trying to retrieve
func getusers(){
ref.child("Friends").child(currentuser!).observe(.childAdded, with: { (snapshot) in
print(snapshot)
if let dic = snapshot.value as? [String: AnyObject]{
let user = User()
user.setValuesForKeys(dic)
print(user.firstname, user.lastname)
DispatchQueue.main.async {
self.tableview.reloadData()
}}
}) { (error) in
print(error.localizedDescription)
}
}
and the crash is here user.setValuesForKeys(dic).
Anyone has any idea why isn't working?
Try this instead:
#objcMembers
class User: NSObject {
...
}
The setValuesForKeys API is implemented by the Foundation framework and requires Objective-C compatibility.
The rules for exposing Swift code to Objective-C have changed considerably in Swift 4. Please check the evolution proposal for further information.
User class design. If any of the four properties can be missing from Firebase than your class design might be a good fit. Otherwise, consider declaring the fixed properties as non-optional and creating an initializer instead.
Change your User declaration to this:
class User: NSObject {
#objc var firstname: String?
#objc var lastname: String?
#objc var username: String?
#objc var profilepic: String?
}
In Swift 4, Objective-C cannot see your instance properties unless you expose them explicitly.

iOS swift singleton clear data

class ShareData {
class var sharedInstance: ShareData {
struct Static {
static var instance: ShareData?
static var token: dispatch_once_t = 0
}
dispatch_once(&Static.token) {
Static.instance = ShareData()
}
return Static.instance!
}
var someString : String! //Some String
var selectedTheme : AnyObject! //Some Object
var someBoolValue : Bool!
}
This is my singleton design.However , I want to know how I can clear all its data as and when required?
Also can i have more than one singleton Class??
Since you've only got 3 properties on your singleton it would be far easier just to set up a method that nils each property in turn.
Once you start getting in to how to destroy and recreate your singleton, you get in to the realm of do you actually even want a singleton or should you just be using a regular object.
You are creating a Singleton with the syntax available in... 2014
Today there's a better syntax to define a Singleton class
final class SharedData {
static let sharedInstance = SharedData()
private init() { }
var someString: String?
var selectedTheme: AnyObject?
var someBoolValue: Bool?
func clear() {
someString = nil
selectedTheme = nil
someBoolValue = nil
}
}
As you can see I also added the clearData() method you were looking for.

Parse PFSubclassing in Swift of Object type

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.

parse.com includeKey: not working

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

Resources