new programmer trying to learn Swift and I'm trying to set my app up to only show the current users post on a parse photosharing database. The first method here in theory should add the current user to the "followingWho" array.
override func viewDidLoad() {
super.viewDidLoad()
let userQuery = PFUser.query()
userQuery?.whereKey("username", equalTo: PFUser.currentUser()!.username!)
userQuery?.findObjectsInBackgroundWithBlock ({
(objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
//no error
if let objects = objects {
for object in objects {
let followingWho = object["followingWho"] as! NSArray!
self.loadData(followingWho)
}
}
} else {
//error
NSLog("Error")
}
})
self.tableView.reloadData()
}
then my second method here should display the posts and filter out all but the current users
func loadData(followingWho: NSArray) {
let query = PFQuery(className: "Posts")
query.whereKey("addedBy", containedIn: followingWho as! [PFObject])
query.orderByDescending("createdAt")
query.findObjectsInBackgroundWithBlock {
(posts: [PFObject]?, error: NSError?) -> Void in
if (error == nil) {
//No error
//let posts = posts as! [PFObject]
if let posts = posts {
for post in posts {
self.images.append(post["Image"] as! PFFile)
self.imageCaptions.append(post["Caption"] as! String)
self.imageDates.append(post["date"] as! String)
self.imageUsers.append(post["addedby"] as! String)
}
self.tableView.reloadData()
}
} else {
//error
NSLog("Error")
}
}
}
But nothing seems to be working. The code compiles and runs but it seems to only pull up a blank screen loading none of the posts.
This could be the problem, although if it is not the problem, it is certainly a problem: you are trying to update the UI from a background thread. findObjectsInBackgroundWithBlock calls its completion block in the background, and updating UI from the background is a big no-no. Instead, call your UI updates on the main thread:
dispatch_async(dispatch_get_main_queue(), {
//Do your UI updates here
})
Related
each cell displays the according comments and photo of the user logged-on. They are loaded with parse.
Now you want to Löschen the button deletes the photo and the comments.
Unfortunately this does not work. Wen I click on the button nothing happens
Unfortunately I understand little of swift and can't get on the solution
The query works, and the app displays the photos and Commons.The query and post code:
override func viewDidLoad() {
super.viewDidLoad()
super.viewDidLoad()
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (object, error) in
if let posts = object {
for post in posts{
print(posts)
self.comments.append(post["message"] as! String)
self.imageFile.append(post["imageFile"] as! PFFile)
self.tableView.reloadData()
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}
And here of the "delete"function code that I have tried:
#IBAction func remove(_ sender: Any) {
print("Entered remove")
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: PFUser.current()?.username)
query.findObjectsInBackground(block: { (object, error) in
if let posts = object {
print(posts)
for post in posts{
print(posts)
if let message = post["message"] as? String, let image = post["imageFile"] as? PFFile {
print("message and image read", message, image)
if let messageIndex = self.comments.index(of: message), let imageIndex = self.imageFile.index(of:image) {
self.comments.remove(at: messageIndex)
self.imageFile.remove(at: imageIndex)
}
}
self.tableView.reloadData()
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
})
}
The output:
I don't get an error message and nothing is deleted.
Thank you for your help
You do not have access to your current index where and object ids.
So based on that you can remove easy.
The more easy way to implement the delete function is to have an array of objectId for your messages:
self.ids.append(post.objectId)
And when you want to delete it:
let query = PFQuery(className: "Post")
query.whereKey("objectId", equalTo: self.ids.index(of: indexPath.row))
// Make a query in background to only get the object that you want to delete
query.getFirstObjectInBackgroundWithBlock {
(object: PFObject?, error: NSError?) -> Void in
if error != nil || object == nil {
print("The getFirstObject request failed.")
} else if let object = object {
print("Successfully retrieved the object.")
object.deleteInBackground()
}
}
Having different arrays representing the same object is not really good to do. So a better way to handle you problem is have only one array for your post
When you fetch it you can do something like that:
guard let user = PFUser.current() else { return }
let query = PFQuery(className: "Post")
query.whereKey("username", equalTo: user.username)
query.findObjectsInBackground(block: { (posts, error) in
if let posts = posts {
self.posts = posts
}
})
With this way when you want to delete it in the remove function:
if indexPath.row < self.posts.count {
self.posts[indexPath.row].deleteInBackground()
}
I am trying to query the user's from _User class, which I have managed successfully. But what I am trying to do now where I'm having a bit of difficulty, is query another class, Posts, and download the images that match the users downloaded from the first query?!
So I am just trying to assign the images from the Posts class to the correct users from the _User class...It sounds very simple, but it driving me mad!!
Here's my code for the query, I know it's probably not the best way but I'm newish to Swift! But I'm willing to try any tips or recommendations if you have any!
let userQuery = PFQuery(className: "_User")
userQuery.addDescendingOrder("createdAt")
userQuery.findObjectsInBackgroundWithBlock ({
(objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.profilePicArray.removeAll(keepCapacity: false)
self.usernameArray.removeAll(keepCapacity: false)
self.fullnameArray.removeAll(keepCapacity: false)
self.uuidArray.removeAll(keepCapacity: false)
for an object in objects! {
self.profilePicArray.append(object.valueForKey("profilePicture") as! PFFile)
self.usernameArray.append(object.valueForKey("username") as! String)
self.fullnameArray.append(object.valueForKey("firstname") as! String)
self.uuidArray.append(object.valueForKey("uuid") as! String)
}
let imageQuery = PFQuery(className: "Posts")
imageQuery.whereKey("username", containedIn: self.usernameArray)
imageQuery.findObjectsInBackgroundWithBlock({ (objects:[PFObject]?, error:NSError?) -> Void in
if error == nil {
self.lastPicArray.removeAll(keepCapacity: false)
for an object in objects! {
self.lastPicArray.append(object.valueForKey("image") as! PFFile)
}
self.collectionView.reloadData()
} else {
print(error!.localizedDescription)
}
})
} else {
print(error!.localizedDescription)
}
})
The result I am getting at the moment is that: all user's download and also all the posts, but the images are just assigned randomly to each user or all the posts appear for each single user!
Thanks in advance.
New Query
func uu() {
let query = PFQuery(className: "_User")
query.addDescendingOrder("createdAt")
query.includeKey("latestImage")
query.whereKey("username", notEqualTo: PFUser.currentUser()!.username!)
query.findObjectsInBackgroundWithBlock { (object:[PFObject]?, error:NSError?) -> Void in
if error == nil {
for object in object! {
if (object.objectForKey("latestImage") != nil)
{
self.lastPicArray.append(object.objectForKey("latestImage")!.valueForKey("image") as! PFFile)
self.profilePicArray.append(object.valueForKey("profilePicture") as! PFFile)
self.fullnameArray.append(object.valueForKey("firstname") as! String)
self.usernameArr.append(object.valueForKey("username") as! String)
}
}
self.collectionView.reloadData()
print(self.usernameArr)
print(self.lastPicArray)
}
}
}
You should be able to do this with just one query, by using the includeKey function of Parse Queries
Parse Queries
Take your 2nd query, and add something like this:
let imageQuery = PFQuery(className: "Posts")
imageQuery.whereKey("username", containedIn: self.usernameArray)
imageQuery.includeKey("fieldNameOfUserPointer")
Just change the 'fieldNameOfUserPointer' to the field name that references your _User object in the Posts entity.
I am trying to build a chat application, but I have a problem with this code:
func loadData() {
let FindTimeLineData: PFQuery = PFQuery(className: "Message")
FindTimeLineData.findObjectsInBackgroundWithBlock { (objects: [AnyObject]!, NSError) -> Void in
self.MessagesArray = [String]()
for MessageObject in objects {
let messageText: String? = (MessageObject as! PFObject) ["Text"] as? String
if messageText != nil {
self.MessagesArray.append(messageText!)
}
}
}
}
I need to retrieve data from Parse, but the .findObjectsInBackgroundWithBlock method tells me that it cannot convert a value of type AnyObject into Void in. How can I resolve this problem? Thanks in advance.
Try it like this instead:
var query = PFQuery(className: "Message")
query.findObjectsInBackgroundWithBlock {
(remoteObjects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
print("Retrieved \(remoteObjects!.count) messages from server.")
self.MessagesArray = [String]() // By convention, you should name this "messagesArray" instead, and initialize it outside this method
for messageObject in remoteObjects {
if let messageText: String? = messageObject["Text"] as? String {
self.messagesArray.append(messageText)
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
(not properly proof-read, but you should be able to get it to work from this)
For the record, there are LOTS of duplicate questions with this problem - i know, as I had the same problem after converting Parse code to Swift 2.1.
So, please do a little more research before you post a question. Often, SO even hints at you similar questions as you are typing...
As for the answer, the Parse API doesn't force you to cast the object as AnyObject anymore in the completion block of a query, so it can look just like this:
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let messages = objects {
for message in messages {
.... etc
My Question is very simple,
I'm Learning iOS development and I'm stuck with tableviewcontroller
I can add Values to tableview with array, but when I try to append value from Parse, it's not working.
Here is the code:
var names: [String] = ["Name_one", "Name_two"]
let query: PFQuery! = PFUser.query()
override func viewDidLoad() {
super.viewDidLoad()
query.whereKey("objectId", notEqualTo: PFUser.currentUser()!.objectId!)
query.findObjectsInBackgroundWithBlock { objects, error in
if (error == nil) {
for user: PFUser in (objects as! [PFUser]) {
self.names.append(user.username as! String)
}
} else {
print("Error")
}
}
Screen Shot Attachment
You must to reload your tableview after get data finished
Code:
query.findObjectsInBackgroundWithBlock { objects, error in
if (error == nil) {
for user: PFUser in (objects as! [PFUser]) {
self.names.append(user.username as! String)
}
yourTableview.reloadData()
} else {
print("Error")
}
}
I have a function that is called in the viewDidLoad of my collectionView that loads content from my server into the view:
// Load Books Class
func loadBooks() {
var query = PFQuery(className: "Books")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
let bookObjects = objects as! [PFObject]
for (index, object) in enumerate(bookObjects) {
self.books.append(Book(pfBook: object))
}
}else if let secondMessage = error?.userInfo?["error"] as? String
where secondMessage == "The Internet connection appears to be offline." {
self.failedMessage(secondMessage)
}
dispatch_async(dispatch_get_main_queue()){
self.collectionView!.reloadData()
}
}
}
And here is my function that is called when the collectionView is refreshed, I basically am attempting to just reload the items back to the view:
func startRefresh(){
dispatch_async(dispatch_get_main_queue()) {
self.loadBooks()
println("loading complete!")
self.refreshControl.endRefreshing()
}
}
However when I refresh, rather than loading the same content again, it loads twice the amount of content.. sort of like calling the load method on top of the load method, rather than re-executing it.. looking at my logic, what should I do to fix the issue?
You need to clear your array before you start adding items. Add self.books.removeAll() to your code, like following:
func loadBooks() {
var query = PFQuery(className: "Books")
query.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
self.books.removeAll()
let bookObjects = objects as! [PFObject]
for (index, object) in enumerate(bookObjects) {
self.books.append(Book(pfBook: object))
}
}else if let secondMessage = error?.userInfo?["error"] as? String
where secondMessage == "The Internet connection appears to be offline." {
self.failedMessage(secondMessage)
}
self.collectionView!.reloadData()
}
}
Edit: Since Parse callbacks are executed on main thread, you don't need the dispatch_async part of your code.
You should remove all children of self.books
self.books.removeAll() before self.books.append(Book(pfBook: object))