I am using parse with Swift and I am trying to bring up and post an image from Parse on to my tableView but I keep receiving in the log
fatal error: unexpectedly found nil while unwrapping an Optional
value
here's my code for querying the image:
import UIKit
import Parse
class HomePage: UITableViewController {
var images = [UIImage]()
var titles = [String]()
var imageFiles = [PFFile]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
println(PFUser.currentUser())
var query = PFQuery(className:"Post")
//query.whereKey("username", equalTo:followedUser)
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
for object in objects! {
// Update - replaced as with as!
self.titles.append(object["Title"] as! String)
// Update - replaced as with as!
self.imageFiles.append(object["imageFile"] as! PFFile)
self.tableView.reloadData()
}
} else {
// Log details of the failure
println(error)
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return titles.count
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 500
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var myCell:cell = self.tableView.dequeueReusableCellWithIdentifier("myCell") as! cell
myCell.rank.text = "21"
myCell.votes.text = "4012"
myCell.postDescription.text = titles[indexPath.row]
return myCell
}
}
Also I get the one line of code highlighted in green which is this :
self.imageFiles.append(object["imageFile"] as! PFFile)
What am I doing wrong and what can I do to make the the code pull up the image from Parse?
now its no longer giving me the error unwrapped nil but it still shows
self.imageFiles.append(object["imageFile"] as! PFFile)
in green highlighting and the app keeps crashing when i open it.
this is my parse backend in case that might be an issue:
i solved the issue by adding in the ovveride func UITableviewCell
imageFile[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
i think this worked because i got rid of the if error == nil and now its working great for me.
Related
I'm working on a message app with parse.
I would like to filter by sender the result of query but it duplicate sender for each messages.
I think it is possible to find same value on a array? (in this exemple clientsArray)
Any idea?
Below the code that I used.
var clientName = ""
var clientsArray:[String] = [String]()
override func viewDidLoad() {
super.viewDidLoad()
//Message List Query
let messages = PFQuery(className:"Message")
messages.whereKey("user", equalTo:PFUser.currentUser()!["retailer"]!)
messages.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
if error == nil {
print("Successfully retrieved \(objects!.count) scores.")
if let objects = objects as? [PFObject] {
self.clientName.removeAll()
for object in objects {
if let clientName = object["clientName"] as? String {
self.clientsArray.append(clientName)
}
self.tableView.reloadData()
print(self.clientsArray)
}
}
} else {
print(error)
}
}
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return clientsArray.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("clientsCell", forIndexPath: indexPath)
let clientName = clientsArray[indexPath.row]
if let clientNameLabel = cell.viewWithTag(301) as? UILabel {
clientNameLabel.text = clientName
}
return cell
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showChat" {
if let destination = segue.destinationViewController as? newChatViewController {
destination.clientName = clientsArray[(tableView.indexPathForSelectedRow?.row)!]
//self.hidesBottomBarWhenPushed = true
}
}
}
It's really hard to answer without seeing what the data structure looks like. But I can tell you the problem with your code.
if let clientName = object["clientName"] as? String {
self.clientsArray.append(clientName)
}
Your if-let statement is simply getting the object of ["clientName"], which is just your clients name. Then you're appending your clients name to your clientsArray object.
This is why you're just seeing luke.
I can help resolve the problem, but I need to know what your data's structure looks like. Can you print out an entire object?
I am attempting to fetch data from an object created on Parse.com into a custom cell that contains labels and images. The code I implemented thus far runs but my tableview remains empty and at runtime displays the following error. ERROR: Thread 1: Exc_BAD_INSTRUCTION (Code =EXC_1386_INVOP, subcode=0x0). Can someone please explain why this is occurring I am new to programming in Xcode.
#objc
protocol ViewControllerDelegate {
optional func toggleLeftPanel()
optional func toggleRightPanel()
optional func collapseSidePanels()
}
class ViewController: UITableViewController, UITableViewDataSource, UITableViewDelegate
{
var delegate: ViewControllerDelegate?
var arrayOfParties: [Information] = [Information]()
#IBAction func menuTapped(sender: AnyObject) {
delegate?.toggleLeftPanel?()
}
override func viewDidLoad()
{
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.loadData()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
{
//return self.arrayOfParties.count
return self.arrayOfParties.count
}
//Function to adjust the height of the custom cell
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
{
return 230
}
override func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
{
let cell: CustomCell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CustomCell
let party = arrayOfParties[indexPath.row]
cell.setCell(party.partyName, promoterLabelText: party.promoterName, partyCostLabelText: party.partyCost, partyFlyerUIImage: party.flyerImage, promoterUIImage: party.promoterImage)
return cell
}
func loadData()
{
var findDataParse:PFQuery = PFQuery(className: "flyerDataFetch")
findDataParse.findObjectsInBackgroundWithBlock{
(objects: [AnyObject]?, error: NSError?)->Void in
if (error == nil){
for object in objects!
{
var party1 = Information(partyName: (object["partyName"] as? String)!, promoterName: (object["promoterName"] as? String)!, partyCost: (object["partyCost"] as? String)!, flyerImage: "", promoterImage: "")
self.arrayOfParties.append(party1)
}
}
else {
// something went wron
}
}
}
}
The problem is that you probably have cells in the tableview already that don't have the new labels/images.
You need to tell the program to insert a type of text where there is no input of the new type.
In this case I have already since a month back worked on a project, and now I started inserting more labels into my cell, thats where the problem pops up, so the previous cells don't have this information.
So I just tell the system to check all cells, if a cell doesn't have the needed text, it should just enter some placeholder text (in this case = "").
if let content = text.objectForKey("Content") as? String {
cell.TextView.alpha = 1.0
cell.TextView.text = content
}
else{
cell.TextView.alpha = 1.0
cell.TextView.text = ""
}
I hope this helps, I have only explained how to do, I haven't really told you were in your code to do it, but from what I see you should input the code right under the part where you declare "Party1".
class FollowingTableTableViewController: UITableViewController {
let usernames = NSMutableArray()
override func viewDidLoad() {
super.viewDidLoad()
getUsernames()
// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem()
}
func getUsernames() {
var user1 = PFUser.currentUser()
var findUsernames:PFQuery = PFQuery(className: "FollowRequests")
findUsernames.whereKey("from", equalTo: user1!)
findUsernames.includeKey("to")
findUsernames.findObjectsInBackgroundWithBlock { (objects: [AnyObject]?, error: NSError?) -> Void in
var myObjects = objects as! [PFObject]
//Solve this part. Need to get all of the users from the "to" field in FollowRequests.
//If No error
if (error == nil) {
for myObjects in objects! {
var user2 = PFUser()
user2.objectForKey("to")
self.usernames.addObject(user2.username!)
println(user2.username)
}
self.tableView.reloadData()
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return self.usernames.count
}
override func tableView(tableView: UITableView,
cellForRowAtIndexPath indexPath: NSIndexPath)
-> UITableViewCell {
let item: AnyObject = self.usernames[indexPath.row]
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel!.text = (usernames[indexPath.row] as! String)
return cell
}
I keep getting the fatal error:
unexpectedly found nil while unwrapping an Optional value.
What do I need to do?
Hoping to find where I messed up.
There is a lot of ? in your code:
First: are you trying to query using the currentUser(username ) or (objectID)
Second: in the findObjectsInBackgroundWithBlock method
you need to check if there is an error first then convert the array of any object to PFObject
if error == nil{
if let objects = objects as! [PFObject]{
for oneSpecificObject in objects{
var data = oneSpecificObject["to"] as! String
self.usernames.addObject(data)
}
self.tableView.reloadData()
}
}
Third: In the cellForRowAtIndexPath method
why you have that extra line
let item: AnyObject = self.usernames[indexPath.row]
//review carefully your code then if you still have problem let me know.
Im trying to make the login form as the main initial screen but i cant, all the time opens user list table first. I dont have any data on Parse but i have all the neccessary classes there. It looks like it have logged in as anonymous user or something and now it makes a lot of errors because there is no suitable code for unknown user? Can somebody help me please?
//
// FeedTableViewController.swift
// ParseStarterProject
//
// Created by Rob Percival on 19/05/2015.
// Copyright (c) 2015 Parse. All rights reserved.
//
import UIKit
import Parse
class FeedTableViewController: UITableViewController {
var messages = [String]()
var usernames = [String]()
var imageFiles = [PFFile]()
var users = [String: String]()
override func viewDidLoad() {
super.viewDidLoad()
var query = PFUser.query()
query?.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let users = objects {
self.messages.removeAll(keepCapacity: true)
self.users.removeAll(keepCapacity: true)
self.imageFiles.removeAll(keepCapacity: true)
self.usernames.removeAll(keepCapacity: true)
for object in users {
if let user = object as? PFUser {
self.users[user.objectId!] = user.username!
}
}
}
var getFollowedUsersQuery = PFQuery(className: "followers")
getFollowedUsersQuery.whereKey("follower", equalTo: PFUser.currentUser()!.objectId!)
getFollowedUsersQuery.findObjectsInBackgroundWithBlock { (objects, error) -> Void in
if let objects = objects {
for object in objects {
var followedUser = object["following"] as! String
var query = PFQuery(className: "Post")
query.whereKey("userId", equalTo: followedUser)
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if let objects = objects {
for object in objects {
self.messages.append(object["message"] as! String)
self.imageFiles.append(object["imageFile"] as! PFFile)
self.usernames.append(self.users[object["userId"] as! String]!)
self.tableView.reloadData()
}
}
})
}
}
}
})
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Potentially incomplete method implementation.
// Return the number of sections.
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete method implementation.
// Return the number of rows in the section.
return usernames.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! cell
imageFiles[indexPath.row].getDataInBackgroundWithBlock { (data, error) -> Void in
if let downloadedImage = UIImage(data: data!) {
myCell.postedImage.image = downloadedImage
}
}
myCell.username.text = usernames[indexPath.row]
myCell.message.text = messages[indexPath.row]
return myCell
}
/*
// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
// Delete the row from the data source
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
} else if editingStyle == .Insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
// Return NO if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
}
A PFUser's objectID is not stored on the device. You need to fetch it. The following is Objective-C but it should be easily converted to swift.
PFQuery *query = [PFUser query];
[query whereKey:#"username" equalTo:[[PFUser currentUser] objectForKey:#"username"]];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
if (objects.count) {
for (PFObject *object in objects) { // just to be safe, but there should only be one.
NSLog(#"Object ID: %#", object.objectId);
}
}
}
}
In Swift (because you asked politely)
var query = PFUser.query()
query.whereKey("username", equalTo:PFUser.currentUser().objectForKey("username"))
query.findObjectsInBackgroundWithBlock({(objects:NSArray, error:NSError) in
if error == nil {
if objects.count {
for var object in objects {
// here you can get object.objectID
}
}
}
})
I really don't know whats going on and Im really confused why this happens. I might be doing something wrong but when i try to access my array out of the function, there is nothing in it. If anyone can help me please tell me.
import UIKit
class withFriendsView: UITableViewController {
var withFriendsArray:NSMutableArray = NSMutableArray()
var friendImg = [PFFile]()
var friendusername = [String]()
var friendName = [String]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
loadWithFriends()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friendusername.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell:WithFriendsCell = tableView.dequeueReusableCellWithIdentifier("withFriends", forIndexPath: indexPath) as! WithFriendsCell
friendImg[indexPath.row].getDataInBackgroundWithBlock {
(data:NSData?, error:NSError?) -> Void in
let img = UIImage(data: data!)
cell.friendsImage.image = img
}
return cell
}
func loadWithFriends() {
var channelQuery = ChannelQuery.query()!
var activityQuery = ActivityQuery.query()!
channelQuery.whereKey("Host", matchesKey: "ActChannel", inQuery: activityQuery)
channelQuery.whereKey("Host", equalTo: "kia495")
var data = channelQuery.findObjects()
if data!.count != 0 {
for objects in data! {
let username = objects["Users"]!!.objectId
let predicate = NSPredicate(format: "objectId == %#", username!!)
var userQuery = PFQuery(className: "_User", predicate: predicate)
var objects = userQuery.findObjects()
for object in objects! {
friendImg.append(object.objectForKey("profileImage") as! PFFile)
}
}
}
}
}
You should reload the table after adding an element to the array
First move loadWithFriends() from viewDidAppear to viewDidLoad
in this line, you are returning another array, try returning friendImg.count
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return friendusername.count
}
This findObjectsInBackgroundWithBlock looks like an async method, which will immediately return. The code in the block will be executed only when the data is ready. So when you try to access the data from friendImg, it may not be ready and you will get nil.
If the data is not very large, you can use sync method to do this.