Swift - 'PFObject is not convertible to NSString' - ios

I've been trying to print the PFQuery called in my viewWillAppear in the cell but I'm getting the error from this line:
cell?.textLabel?.text = message as NSString as String
Here's the code for the tableView cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellId: NSString = "cell"
var cell: UITableViewCell? = tableView.dequeueReusableCellWithIdentifier(cellId as String) as? UITableViewCell
if (cell == nil) {
cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: cellId as String)
}
let message = myMessagesArray![indexPath.row] as! PFObject
cell?.textLabel?.text = message as NSString as String
return cell!
}
Here's the PFQuery:
var query = PFUser.query()
query!.orderByAscending("Messages")
query!.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
println("Successfully retrieved \(objects!.count) messages.")
self.myMessagesArray = objects
self.tableView?.reloadData()
} else {
println(error!.localizedDescription)
}
}

Use this code:
let message = myMessagesArray[indexPath!.row] as! PFObject
cell.textLabel?.text = message.objectForKey("Messages") as? String

Related

Async With Parse

I'm building an app based around pictures. So it's very important for me to retrieve all images asyncronously like Instagram does. I understand that this function...
var query = PFQuery(className: "Post")
query.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects as! [PFObjects] {
for object in objects {
objectsArray.append(object)
}
}
}
...is asynchronous. But I want a way to load images from Parse into a table asynchronously so it loads images while scrolling.
You should take a look at PFImageView's function loadInBackground().
For example, if you are using a PFTableViewController with a PFTableViewCell, you can do the following
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("CustomCell") as! CustomTableViewCell!
if cell == nil {
cell = CustomTableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "CustomCell")
}
if let name = object?["name"] as? String {
cell.nameLbl.text = name
}
var initialThumbnail = UIImage(named: "placeholder")
cell.imgView.image = initialThumbnail
if let thumbnail = object?["photo"] as? PFFile {
cell.imgView.file = thumbnail
cell.imgView.loadInBackground()
}
return cell
}
with PFTableViewCell having
class CustomCell: PFTableViewCell {
#IBOutlet weak var nameLbl: UILabel!
#IBOutlet weak var imgView: PFImageView!
}
Also from another SO reply, you can try this:
let userImageFile = userPhoto["imageFile"] as PFFile
userImageFile.getDataInBackgroundWithBlock {
(imageData: NSData!, error: NSError!) -> Void in
if !error {
let image = UIImage(data:imageData)
}
}

Fetching data unordered with predicate from array

Here is function where I try to fetch images from parse for users that are in the namesArray.
func fetchData(){
let imagePredicate = NSPredicate(format: "username IN %#", namesArray)
let imageQuery = PFQuery(className: "_User", predicate: imagePredicate)
imageQuery.findObjectsInBackgroundWithBlock { (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object in objects! {
self.imagesArray.append(object["image"] as! PFFile)
if self.imagesArray.count == self.namesArray.count {
self.tableView.reloadData()
}
} else {
print("error: \(error?.localizedDescription)")
}
}
}
Here is my tableView:cellForRowAtIndexPath method:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ChatsCell
cell.nameLabel.text = namesArray[indexPath.row]
if imagesArray.count == namesArray.count && self.imagesLoaded == false{
imagesArray[indexPath.row].getDataInBackgroundWithBlock { (imageData: NSData?, error: NSError?) -> Void in
if error == nil {
let image = UIImage(data: imageData!)
cell.imageView?.image = image
self.tableView.reloadData()
self.imagesLoaded = true
}
}
}
return cell
}
But when I do so I see that images are not synchronised with names of the users. Even if I put my users in other order images will stay in the same order as they was before.
How can I change it?
Not sure what you're asking here. Is it that you were expecting the images to be returned in an array sorted by the user?
If so, then you will need to add a sort order to your PFQuery. I suggest you sort your namesArray by username, and then also sort the imageQuery by username:
imageQuery.orderByDescending("username")
Hope I understood the question ;]
--T
So I found that if you use one query you will receive ordered data so I've changed my code and now it works pretty well. So what I've done is that I do query for every separate member of the namesArray:
func fetchData() {
for index in 0..<self.namesArray.count {
let imagePredicate = NSPredicate(format: "username == %#", namesArray[index])
let imageQuery = PFQuery(className: "_User", predicate: imagePredicate)
imageQuery.findObjectsInBackgroundWithBlock({ (objects: [PFObject]?, error: NSError?) -> Void in
if error == nil {
for object in objects! {
self.imageFilesArray![index] = object["image"] as? PFFile
}
for imageFile in self.imageFilesArray! {
let index = self.imageFilesArray?.indexOf{$0 == imageFile}
imageFile?.getDataInBackgroundWithBlock({ (imageData: NSData?, error: NSError?) -> Void in
let userImage = UIImage(data: imageData!)
self.imagesArray?[index!] = userImage
self.tableView.reloadData()
})
}
}
})
}
}
and here is tableView:cellForRowAtIndexPath:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! ChatsCell
cell.nameLabel.text = namesArray[indexPath.row]
cell.messageTextLabel.text = messagesArray[indexPath.row]
cell.chatImageView.image = self.imagesArray![indexPath.row] != nil ? self.imagesArray![indexPath.row] : UIImage(named: "add")
return cell
}

'[AnyObject]?' is not convertible to 'NSArray'(xcode,swift)

The error is in let USER:PFUser... It was working good but when I updated Xcode this problem appeared. The name of the username is not being displayed.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let postcells: postsTableViewCell = tableView.dequeueReusableCellWithIdentifier("PostCell", forIndexPath: indexPath) as! postsTableViewCell
let Post:PFObject = self.PostData.objectAtIndex(indexPath.row) as! PFObject
postcells.postTimetextView.text = Post.objectForKey("Content") as! String
var dateFormatter:NSDateFormatter = NSDateFormatter()
dateFormatter.dateStyle = NSDateFormatterStyle.NoStyle
dateFormatter.timeStyle = NSDateFormatterStyle.ShortStyle
postcells.timeStamp.text = dateFormatter.stringFromDate(Post.createdAt!)
var findPostedBy:PFQuery = PFUser.query()!
findPostedBy.whereKey("objectId", equalTo: Post.objectForKey("Postedby")!)
findPostedBy.findObjectsInBackgroundWithBlock{
(objects, error) -> Void in
if error == nil {
let USER:PFUser = (objects as NSArray).lastObject as! PFUser
postcells.usernameLabel3.text = USER.username
}
}
return postcells
}
You need to make sure that an array was returned from parse
You can use this:
findPostedBy.findObjectsInBackgroundWithBlock{
(objects, error) -> Void in
if error == nil {
if objects?.count > 0 {
let USER:PFUser = objects!.last as! PFUser
// Avoid updating the UI on a background thread
dispatch_async(dispatch_get_main_queue(), { () -> Void in
postcells.usernameLabel3.text = USER.username
})
}
}
}

Parse - imageView as PFFile won't load

I don't understand what is going on. I have an image saved as a PFFile in Parse. I can see it and I know it is there. I want to have it as a cell image. The rest of the code below works fine and the memory addresses of PFFile also print. textLabel and detailTextLabel also fine but the images won't show (even if I delete 'loadInBackground'). Any ideas?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath, object: PFObject?) -> PFTableViewCell? {
var cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! PFTableViewCell!
if cell == nil {
cell = PFTableViewCell(style: .Subtitle, reuseIdentifier: "Cell")
}
if let name = object?["name"] as? String {
cell.textLabel?.text = name
}
if let artist = object?["artist"] as? String {
cell.detailTextLabel?.text = artist
}
if let artwork = object?["artwork"] as? PFFile {
println("we've got an artwork image \(artwork)")
//cell!.imageView!.image = UIImage(named: "placeholder.jpg")
cell.imageView?.file = artwork
cell.imageView?.loadInBackground()
}
return cell
}
Parse just saves an reference to the image in the table, you will have to do another async call to retrieve the message.:
let artwork = object?["artwork"] as PFFile
artwork.getDataInBackgroundWithBlock {
(imageData: NSData?, error: NSError?) -> Void in
if error == nil {
if let imageData = imageData {
let image = UIImage(data:imageData)
}
}
}

Load JSON into UItableView in Swift

I've been trying to return string urls from JSON and store it in array and then show the array in UITableView. but it shows empty UILabel.
class PhotosTableViewController: UITableViewController {
let imageLoadURL = "https://..."
var TAG_IMG_URL = []
verride func viewDidLoad() {
super.viewDidLoad()
getLatestPhotos()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TAG_IMG_URL.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! KivaLoanTableViewCell
cell.nameLabel.text = TAG_IMG_URL[indexPath.row] as? String
return cell
}
func getLatestPhotos() {
let request = NSURLRequest(URL: NSURL(string: imageLoadURL)!)
let urlSession = NSURLSession.sharedSession()
let task = urlSession.dataTaskWithRequest(request, completionHandler: { (data, response, error) -> Void in
if error != nil {
println(error.localizedDescription)
}
self.TAG_IMG_URL = self.parseJsonData(data)
println("\(self.TAG_IMG_URL.count)")
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
})
})
task.resume()
}
func parseJsonData(data: NSData) -> NSArray {
var error:NSError?
let jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as? NSDictionary
if error != nil {
println(error?.localizedDescription)
}
if let j = jsonResult, let mediaObjects = j.valueForKeyPath("feed.entry.media$group.media$content") as? NSArray {
if let imageUrls: AnyObject = mediaObjects.valueForKey("url") {
TAG_IMG_URL = imageUrls as! NSArray
}
}
println("\(TAG_IMG_URL)")
self.alert.dismissWithClickedButtonIndex(0, animated: true)
return TAG_IMG_URL
}
}
During parseJsonData it returns the urls which it look like (below), but when i try to show it in the UITableView it always becomes empty UILabel so what am i doing wrong here ?:
(
(
"https://..."
),
(
"https://..."
)
)
Note : in numberOfRowsInSection it returns the right amount which its 2 urls.
Try this:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! KivaLoanTableViewCell
cell.nameLabel.text = TAG_IMG_URL[indexPath.row][0] as? String
return cell
}
The problem that you have 2-dimensional array, so you should get first object in object:
TAG_IMG_URL[indexPath.row].firstObject or TAG_IMG_URL[indexPath.row][0].

Resources