Getting username of Parse user - swift

I have code that i am trying to get a username of a PFUser. I'm getting the user and able to print it out, but when I get to the line for the username, the code just stops. No crash nothing, just stops running?
Any ideas why it would do that?
print(employeeObject)
firstName.text = employeeObject.firstName
lastName.text = employeeObject.lastName
if employeeObject.roleType != nil {
roleLabel.text = employeeObject.roleType?.roleName
}
if employeeObject.objectForKey("userPointer") != nil {
employeeObject.userPoint = employeeObject.objectForKey("userPointer") as! PFUser
}
if employeeObject.userPoint != nil {
let userID = employeeObject.userPoint!.objectId!
let query = PFUser.query()
query?.whereKey("objectId", equalTo: userID)
query?.getFirstObjectInBackgroundWithBlock({ (userData : PFObject?, error : NSError?) in
print(userData)
self.userLoginSwitch.setOn(true, animated: false)
self.userNameTextField.text = self.employeeObject.userPoint?.username!
self.passwordTextField.text = ""
self.emailAddressTextField.text = self.employeeObject.userPoint!.email
if self.employeeObject.userPoint!.objectForKey("isAdmin") as! Bool {
self.adminSwitch.setOn(true, animated: false)
}
})
}
if employeeObject.active {
disableEnableEmployee.setTitle("Disable Employee", forState: .Normal)
} else {
disableEnableEmployee.setTitle("Enable Employee", forState: .Normal)
disableEnableEmployee.setTitleColor(UIColor.blueColor(), forState: .Normal)
}
I have userPoint casted as a PFUser, and then in Parse i have it pointed to the User table, and when i print. i can see all the information. It just stops working thought, with no error or explanation.
var userPoint : PFUser? {
get {return objectForKey("userPointer") as? PFUser}
set { setObject(newValue!, forKey: "userPointer") }
}

When you fetching objects from Parse pointer objects are not included by default. There is only PFObject with objectId. If you want to include all of properties of pointer you need to use includeKey method with name of pointer. So if you get employeeObject from query (somewhere earlier) you should add line:
employeeQuery.includeKey("userPointer")
In this solution you wont need to get this user again because its the same object.
#Mazels answer is the second solution. You getting the same user by objectId so you can read data from usedData
self.userNameTextField.text = userData["username"]
self.emailAddressTextField.text = userData["email"]
if userData["isAdmin"] as! Bool { ...
Last thing:
if employeeObject.objectForKey("userPointer") != nil {
employeeObject.userPoint = employeeObject.objectForKey("userPointer") as! PFUser
}
This is redundant. Look at your implementation of userPoint and this if statement. It really do nothing :)

if you want to print the username from the query it has to be from the object that is returned, in your case userData and are you sure you dont have any break point in your code if it just stops?
self.userNameTextField.text = userData.username

Related

Core data does not save the data properly

EDITED
I have a UITableView which displays multiple social media posts. I use the Prefetch Source Delegate for prefetching Posts and I use Core Data to be stored after being fetched from web server. Problem that I have is that I get no error, but the data does not stay saved between launches in CoreData.
Snip of code
func configureDataSourceTable(){
self.dataSource = UITableViewDiffableDataSource<String,String>(tableView: self.table_view){
(tableView, indexPath, ref) -> UITableViewCell? in
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CheckInCell
if !self.postData.currentPostFetching(ref: ref){
self.postData.fetchPost(ref: ref) { post in
DispatchQueue.main.async {
self.setPostNeedsUpdate(ref: ref)//reconfigure items
}
return cell
}
func fetchPost(ref: String,completion : (PostStruct)->Void) {
if self.dataContainer.postIsPartOfCoreData(ref: ref){
var postStruct = self.dataContainer.getPostStructFromDB(ref: ref)
completion(postStruct)
}else{ //has to be downloaded from web server
Task {
let post = await getPostFromServer()//not relevant in understanding problem
var postStruct = self.convertDataToPost(post)
completion(postStruct)
self.dataContainer.savePostStruct(post: postStruct)
}
}
}
Class of the DataContainer subclass of NsPersistentStore
func savePostStruct(post_struct : PostStruct,image_data : String){
Task.detached {
var postObject = PostCore.init(context : self.viewContext)
postObject.name = "Test"
var image = ImageCore.init(context: self.viewContext)
imageObject.data = image_data
postObject.image = imageObject
do {
if Thread.isMainThread {
print("Running on the main thread parent")
}else {
print("Other thread")
}
try self.viewContext.save()
print("Reference \(post_struct.ref) child saved")
}catch {
print("Error that produced \(post.ref) catched while trying to savethe data on child: \(error.localizedDescription),number : \(error)");
}
if post_struct.ref == "AAAA"{
var post = PostCore.fetchRequest()
var predicate = NSPredicate.init(format: "ref like %#", post.ref!)
fetchCheckIn.predicate = predicate
fetchCheckIn.fetchLimit = 1
fetchCheckIn.includesPropertyValues = true
let result = try! self.viewContext.fetch(fetchCheckIn)
print(result)
//This line returns the Object
print(self. checkPostExistHasPictures(refPost: post.ref))
//This is the line where always come (false, false) meaning that the Post is not saved
}
}
func getPostStructFromDB(refPost : String)async->PostStruct {
return await self.viewContext.perform{
var fetchPost = PostCore.fetchRequest()
var predicate = NSPredicate.init(format: "ref like %#", refPost)
fetchPost.predicate = predicate
fetchPost.fetchLimit = 1
fetchPost.includesSubentities = true
fetchPost.returnsObjectsAsFaults = false
fetchPost.includesPropertyValues = true
let result = try? self.viewContext.fetch(fetchCheckIn)
var refPost = result.first.ref
return PostStruct(ref : ref, image: refPost.image.data)
}
}
}
func checkPostExistHasPictures(refPost : String)->(Bool,Bool){
var fetchCheckIn = CheckInCore.fetchRequest()
var predicate = NSPredicate.init(format: "ref like %#", refPost)
fetchCheckIn.predicate = predicate
fetchCheckIn.fetchLimit = 1
var exist = false
var hasPicture = false
self.viewContext.performAndWait {
do{
let result = try? self.viewContext.fetch(fetchCheckIn)
if result?.first == nil {
}else {
print("Exists with reference \(reference_checkin)")
if result!.first!.pic_ref == nil {
exist = true
hasPicture = false
}else if result!.first!.image!.count != 0 {
exist = true
hasPicture = true
}
}
}catch {
print("error catched")
}
}
return(exist, hasPicture)
}
}
Relation between PostCore and ImageCore is zero to many.
I don't get any error code or error message. I commented the line where I get the error. I have tried all possible ways using a backGroundContext each time a save is made to not block the main thread and still is the same problem.
Your code is extremely confusing.
Why have you got Task scattered everywhere, you are doing no async/await work?
Your savePostStruct method takes a parameter called post which contains your data, then you immediately replace it with a value of the same name of type PostCore, which is presumably a managed object, then you only set one value on it.
Then, when you come to fetch an item, there's nothing there, because you haven't written anything to the managed object besides the name "Test".
At the very least, you have to change this line:
var post = PostCore.init(context : self.viewContext)
To
let postObject = PostCore(context: self.viewContext)
Then you won't get confused between the managed object and the struct you're passing in.
You are also saving the context before you've written any of the values to it.

Else on If Else statement won't get triggered, can't understand why

I have this block of code:
func fetchFriends() {
if let window = UIApplication.shared.keyWindow {
guard let userId = Auth.auth().currentUser?.uid else { return }
DispatchQueue.main.async {
FirestoreService.shared.fetchFriendList(userId) { (fetchedFriends) in
//// WONT GET HERE ////
if fetchedFriends != nil {
self.fetchedFriends = fetchedFriends! // Can force unwrap here because we already know that fetchedFriends in not nil.
self.friendsTable.reloadData()
}else {
self.fetchedFriends = []
self.friendsTable.reloadData()
}
}
}
}
}
This block of code is using this function:
func fetchFriendList(_ id: String, completion: #escaping([Friend]?)->()) {
var fetchedFriends: [Friend] = []
db.collection(USERS_COLLECTION).document(id).getDocument { (doc, err) in
if err == nil && doc != nil {
guard let results = doc?.data()?[USER_FOLLOWING] as? [String: Any] else { return }
for result in results { // Getting the data in firebase
if let resultValue = result.value as? [String: Any] { // Getting only the value of the MAP data, we do not need the key.
//Getting the fields from the result
guard let id = resultValue[FRIEND_ID] as? String else { return }
guard let profilePic = resultValue[FRIEND_PROFILE_PIC] as? String else { return }
guard let username = resultValue[FRIEND_NAME] as? String else { return }
guard let email = resultValue[FRIEND_MAIL] as? String else { return }
//Creating a new Friend object from the fields
let friend = Friend(id: id, profilePicture: profilePic, username: username, email: email)
fetchedFriends.append(friend)
}
completion(fetchedFriends)
}
}else {
print(err!.localizedDescription)
completion(fetchedFriends)
}
}
}
Whats happening here, is that I'm going into a user's document, getting it's 'Friends' from a Map I have in the document, creating a Friend Array and sending it in the completion to the first function.
In the first function, I'm checking if what I got is nil, if not, I'm assigning it to an array, else, if it is nil, I want the array to be empty.
The purpose here is to show the "Friends" in the tableView if the user has any.
My problem is this situation:
For start, the list of friends is empty, adding a friend and viewing the list, the friend I just added is showing, which is good. the problem is, when I'm removing this friend from the list (and it is deleted in the Database in Firestore), showing the list again does not deletes him from the list and still showing it.
It seems that after removing a friend from the "following" section, and showing the list again, after FirestoreService.shared... it just returns and won't get to the "Won't get here" line.
The FetchFriends() function does gets called everytime I'm opening the FriendsList.
This is a picture of the list I'm referring to, this demouser is removed from the friends list but still showing up.
EDIT: Just noticed that when I have more than one user on the list, it does gets deleted and it works as I want. When I have just one user (or just one left on the list) it won't delete it.
fetchFriendList never calls the callback with a nil value:
var fetchedFriends: [Friend] = []
Therefore your else branch is unnecessary and the completion handler could be #escaping ([Friend]) -> Void without optionals.
By the way, there is also a situation when your method does not call completion at all:
guard let results = doc?.data()?[USER_FOLLOWING] as? [String: Any] else { return }
In general, there are many unsafe places. For example, when err is nil and doc is nil, then your else will crash unwraping err!.
A better alternative:
guard err == nil, let doc = doc else {
print(err?.localizedDescription)
completion([])
return
}
let results = (doc.data()?[USER_FOLLOWING] as? [String: Any]) ?? [:]
let fetchedFriends = results.compactMap { result in
guard
let resultValue = result.value as? [String: Any],
let id = resultValue[FRIEND_ID] as? String,
let profilePic = resultValue[FRIEND_PROFILE_PIC] as? String,
let username = resultValue[FRIEND_NAME] as? String,
let email = resultValue[FRIEND_MAIL] as? String
else { return nil }
return Friend(id: id, profilePicture: profilePic, username: username, email: email)
}
completion(fetchedFriends)

CloudKit how to modify existing record (swift 3)

How can I modify an existing CloudKit record?
I receive a record from CloudKit with this code:
let name = tmpVar as! String
let container = CKContainer.default()
let privateDatabase = container.privateCloudDatabase
var predicate = NSPredicate(format: "email == %#", name)
var query = CKQuery(recordType: "MainTable", predicate: predicate)
privateDatabase.perform(query, inZoneWith: nil) { (results, error) -> Void in
if error != nil {
pass
}
else {
if (results?.count)! > 0 {
for result in results! {
self.likedArr.append(result)
}
if let checker = self.likedArr[0].object(forKey: "like") as? String {
print ("CHEKER IS \(checker)")
let intChecker = Int(checker)
let result = intChecker! + 1
} else {
print ("EMPTY")
}
} else {
print ("Login is incorrect")
}
OperationQueue.main.addOperation({ () -> Void in
// self.tableView.reloadData()
// self.tableView.isHidden = false
// MBProgressHUD.hide(for: self.view, animated: true)})}
and how to return it back modified value of "like" key to the owner "name"?
When you get the records from the cloud, you can cast them to CKRecords.
In this CKRecord object you just modify the values you want to update, and then save it all again to the cloud. The CKRecordId must be the same, otherwise you'll just make a new record.
here is how to modify the records:
MyCKRecord.setValue(object, forKey: "myKey")
When you call the query, you get an array of CKRecord objects. Use the subscript to edit the record:
record["key"] = value as CKRecordValue
when you're finished, take the CKRecord and use either CKModifyRecordsOperation or CKDatabase.save(_:completionHandler:) to save it back to the server.
Sharing my solution:
self.likedArr[0].setValue(1, forKey: "like")
let saveOper = CKModifyRecordsOperation()
saveOper.recordsToSave = self.likedArr
saveOper.savePolicy = .ifServerRecordUnchanged
saveOper.modifyRecordsCompletionBlock = { savedRecords, deletedRecordIDs, error in
if saveOper.isFinished == true {
}
}
privateDatabase.add(saveOper)

Optional in text view showing when printing

Hi all I have tried a few solutions but no luck.
I am getting the text from Data Core, but the textview has optional on it.
when it prints it shows optional in the text.
page22TextView?.text = ("\(trans.value(forKey: "page22"))")
can anyone shed light on this ! have tried to unwrap but it stillelow: shows.
the full function is below:
func getTranscriptions () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<TextInputs> = TextInputs.fetchRequest()
do {
//go get the results
let searchResults = try getContext().fetch(fetchRequest)
//I like to check the size of the returned results!
print ("num of results = \(searchResults.count)")
//You need to convert to NSManagedObject to use 'for' loops
for trans in searchResults as [NSManagedObject] {
page22TextView?.text = ("\(trans.value(forKey: "page22"))")
//get the Key Value pairs (although there may be a better way to do that...
print("\(trans.value(forKey: "page22"))")
}
} catch {
print("Error with request: \(error)")
}
}
try to set default value of getting nil value
page22TextView?.text = (trans.value(forKey: "page22") as? String) ?? ""
It'll set your value from trans and if it retrun nill will be set by "".
Hope it'll help you.
try with if-let statement:
if let result = trans.value(forKey: "page22") {
page22TextView?.text = result
}
Or try with guard statement:
guard let result = trans.value(forKey: "page22") else { return }
page22TextView?.text = String(describing: result)
Or you can force upwrap it like:
let result = trans.value(forKey: "page22")
if result != nil {
page22TextView?.text = result! as! String
}
Or you can follow the way suggested by #MrugeshTank below in answers
try to unwrap optional using if let then assign to your textview (if necessary then downcast your value)
if let value = trans.value(forKey: "page22") {
page22TextView?.text = value
}
or
use guard for unwrap

Can't I use nil for 'undefined' on parse?

I am making a simple app, and implementing the userInformation part. The user can edit his info, but I have trouble that if user doesn't put any info, it will crash when I try to retrieve data from an undefined column.
This is my code to retrieve the user data.now I can check a specific value, but still, I got a error with 'undefined' one.
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
let nickname = (obj.objectForKey("text")) as! String
if (nickname != nil) {
///// I have a error message that binary operator'!=' cannot be applied to operands of type 'String' and 'NiLiteralConvertible'
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
what is the 'NiLiteralConvertible' ?
and I've tried this as well,
var query = PFQuery(className: "Note")
query.getObjectInBackgroundWithId("kg8KhAWCms", block: {
(obj, error)in
if let obj = obj! as? PFObject {
let nickname = (obj.objectForKey("text")) as! String
if !(nickname.isEmpty) {
self.nickNameLabel.text = nickname
}else{
self.nickNameLabel.text = "you don't have a nick name"
}
} else {
print(error)
}
})
So I am asking how can I handle retrieving undefined value before crash? (please write full code for me)
///like this
if (undefined in parse == somekindOfType) {
print("yes")
}
You can't use nickname != nil because you have already said that it cannot be nil with let nickname = (obj.objectForKey("text")) as! String.
The as! String unwraps the obj.objectForKey("text") and at which it cannot be nil or you will get an error.
I suggest using the following:
if let nickname = obj.objectForKey("text") as? String {
self.nickNameLabel.text = nickname
}
else{
self.nickNameLabel.text = "you don't have a nick name"
}
Perhaps this would be beneficial to read: Swift Literal Convertibles