i am making app which have a tableviw and when first time api called table showing data perfectly but when secondtime i open slide out menu and click on button api is calling again and its getting crash on line self.tableView.reloadData().
here is my code in MainViewController
func web()
{
let url = "http://\(urlString)\(slug)"
print(url)
print(slug)
request(.GET, url, parameters: nil, encoding: .JSON).responseJSON { (response:Response<AnyObject, NSError>) -> Void in
if (response.result.value != nil)
{
print(response.result.value)
self.arraypost.removeAllObjects()
print(self.arraypost)
self.arraypost = (response.result.value)?.valueForKey("posts") as! NSMutableArray
print(self.arraypost)
dispatch_async(dispatch_get_main_queue(), {() -> Void in
self.tableView.reloadData()
})
}
}
}
here is mycode in RightViewController
#IBAction func btnmotogp(sender: AnyObject) {
slug = motogp
MainViewController().web()
self.slideMenuController()?.closeRight()
}
just stuck in this problem and wasted too much time on this.
this is the code for tableview
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arraypost.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : mainviewcell = tableView.dequeueReusableCellWithIdentifier("mainviewcell") as! mainviewcell
let dic : NSDictionary = arraypost.objectAtIndex(indexPath.row) as! NSDictionary
cell.lbldate.text = dic["date"] as? String
cell.lblsummary.text = dic["excerpt"] as? String
cell.lbltitle.text = dic["title"] as? String
let myarray : NSMutableArray = (dic["attachments"] as? NSMutableArray)!
print(myarray)
let dic1 : NSDictionary = myarray.objectAtIndex(0) as! NSDictionary
print(dic1)
var newimage : String = ""
newimage = dic1["url"] as! String
print(newimage)
if (newimage.characters.count != 0)
{
ImageLoader.sharedLoader.imageForUrl(newimage) { (images, url) -> () in
if (images != nil)
{
cell.image1.image = images!
}
}
}
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let storyboard = UIStoryboard(name: "SubContentsViewController", bundle: nil)
let subContentsVC = storyboard.instantiateViewControllerWithIdentifier("SubContentsViewController") as! SubContentsViewController
self.navigationController?.pushViewController(subContentsVC, animated: true)
}
It is a bit hard to find out what is where and how exactly you uses it but my guess is that when you call MainViewController().web() the MainViewController's view is not in the views hierarchy so tableView is neither. This provides us to the case when you are calling table to reload but it is not instantiated so it crashes. Make sure that view controller is added correctly.
It would be also nice if you could care about possible retain cycles that blocks can create :)
Related
I have a detail view that shows the details of an event, the people who participate and the people who asked to participate. I have created two arrays of different types but they have the same fields, only that a first structure represents the users with the 'status_confirm' field equal to 1 (therefore Accepted Users), while the other has as 'status_confirm' equal to 0 (Users awaiting acceptance). I declared two arrays, the first one: var arrayUserAccepted = [User_accepted] ().
The second one: var arrayUserWaiting = [User_waiting] (). Struct Image
Next step: I populate these structures via a php script
func getData(){
let url = URL(string: “MYURL”)
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as! [String:AnyObject]
print("JSON: \n\(json)\n")
let waiting = json["waiting"] as! [AnyObject]
let accepted = json["accepted"] as! [AnyObject]
DispatchQueue.main.async {
for list_user_waiting in waiting {
let id_user_waiting = list_user_waiting["id_user”] as! String
let name_user_waiting = list_user_waiting[“name_user”] as! String
let email_user_waiting = list_user_waiting["email"] as! String
var photo_user_waiting = list_user_waiting[“photo”]
let status_user_waiting = list_user_waiting["status”] as! String
if photo_user_waiting is NSNull {
photo_user_waiting = ""
}
let listUserWaiting = User_waiting(id_user_waiting: id_user_waiting, name_user_waiting: name_user_waiting, email_user_waiting: email_utente_attesa, foto_waiting: photo_user_waiting as! String, status_waiting: status_user_waiting)
self.arrayUserWaiting.append(listUserWaiting)
self.tableViewListUserWaiting.reloadData()
}
for list_user_accepted in accepted {
let id_user_accepted = list_user_accepted["id_utente"] as! String
let name_user_accepted = list_user_accepted["name_utente"] as! String
let email_user_accepted = list_user_accepted["email"] as! String
var photo_user_accepted = list_user_accepted[“photo"]
let status_user_accepted = list_user_accepted["status”] as! String
if photo_user_accepted is NSNull {
photo_user_accepted = ""
}
let listUserAccepted = User_accepted(id_user: id_user_accepted, nome_utente: name_user_accepted, email: email_user_accepted, foto: photo_user_accepted as! String, stato: status_user_accepted)
self.arrayUserAccepted.append(listUserAccepted)
self.tableViewListUserAccepted.reloadData()
}
}
} catch let error as NSError {
print(error)
}
}).resume()}
This above is a function that I call in the viewDidLoad(). The next step would be to use the functions of the table view and it is here that I think there is the injunction
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == self.tableViewListUserAccepted {
count = arrayUserAccepted.count
}
if tableView == self.tableViewListUserWaiting {
count = arrayUserWaiting.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
if tableView == self.tableViewListUserAccepted {
cell.imageProfileUserAccepted.image = UIImage(named: "imageDefault")
cell.valueSliderUserAccepted.value = Float(50) //JUST FOR POPULATE THE INTERFACE
cell.name_user_accepted.text = arrayUserAccepted[indexPath.row].name_user
}
if tableView == self.tableViewListUserWaiting {
cell.imageProfileUserWaiting.image = UIImage(named: "imageDefault")
cell.valueSliderUserWaiting.value = Float(23) //JUST FOR POPULATE THE INTERFACE
cell.name_user_waiting.text = arrayUserWaiting[indexPath.row].name_user_waiting
}
return cell
}
Once done all this round, I start the application but nothing. The tables are empty. In the console the script answers me correctly and so I can not figure out where the error could be. Needless to say, I have declared the .delegate and .dataSource of both tables, both in the Main.Storyboard and in the code.
Everything is fine just change the format of IF condition and it will work.
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int?
if tableView == self.tableViewListUserAccepted {
count = arrayUserAccepted.count
} else {
count = arrayUserWaiting.count
}
return count!
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if tableView == self.tableViewListUserAccepted {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.imageProfileUserAccepted.image = UIImage(named: "imageDefault")
cell.valueSliderUserAccepted.value = Float(50) //JUST FOR POPULATE THE INTERFACE
cell.name_user_accepted.text = arrayUserAccepted[indexPath.row].name_user
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.imageProfileUserWaiting.image = UIImage(named: "imageDefault")
cell.valueSliderUserWaiting.value = Float(23) //JUST FOR POPULATE THE INTERFACE
cell.name_user_waiting.text = arrayUserWaiting[indexPath.row].name_user_waiting
return cell
}
}
Also check if the datasource and delegate of both of your tableView are set. Finally call the tableView.reloadTable() method on both of your tableviews after you populate your arrays in the viewDidLoad() method.
I have a tableview with custom cells, when I click on one of my cells it shows me the next viewcontroller ( which is the details of the view controller ) as it should be, the details that assigned to this cell ( received from JSON and saved locally as dictionary ) is totally wrong and when click back and re enter this cell gives me right things as my expectations
Any explanation please?
My code
Here how I fetch the data
func getMyNotifications() {
Alamofire.request("\(Constant.GetMyNotifications)/-1", method: .get, encoding: JSONEncoding.default , headers: Constant.Header ).responseJSON { response in
if let Json = response.result.value as? [String:Any] {
if let ActionData = Json["ActionData"] as? [[String:Any]] {
self.myNotifications = ActionData
self.generalNotifications = ActionData
//
self.myNotificationsTV.reloadData()
self.counter.text = "\(ActionData.count)"
self.myNotifications.reverse()
self.animationView.isHidden = true
self.animationView.stop()
self.refreshControl.endRefreshing()
}
if self.myBalaghat.count == 0 {
self.myNotificationsTV.isHidden = true
self.counter.text = "no notificatins to show"
} else {
self.myNotificationsTV.isHidden = false
}
}
}
}
Here is my cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if segmented.selectedSegmentIndex == 0 {
return returnCell(balaghat: myNotificationsTV, withData: myNotifications, inCell: indexPath.row)
} else {
return returnCell(balaghat: myNotificationsTV, withData: allNotifications, inCell: indexPath.row)
}
}
My didSelectRowAt
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
generalNotifications.reverse()
let prepareNum = generalNotifications[indexPath.row]["Id"] as? NSNumber
currentBalaghId = Int(prepareNum!)
clickedIndex = indexPath.row
if let text = generalNotifications[indexPath.row]["NotifDateG"] as? String {
prepareDateforPassing = text
}
if let text = generalNotifications[indexPath.row]["Description"] as? String {
prepareDesciptionforPassing = text
}
if let text = generalNotifications[indexPath.row]["TypeName"] as? String {
prepareTypeforPassing = text
}
if let text = generalNotifications[indexPath.row]["AddedByName"] as? String {
prepareProviderNameforPassing = text
}
self.performSegue(withIdentifier: "showDetails", sender: self)
// to remove highlighting after finish selecting
tableView.deselectRow(at: indexPath, animated: true)
}
It seems you are doing reverse on your myNotifications array after tableView's reloadData called. So try reload your tableView once you have reversed your myNotifications array as like below.
if let ActionData = Json["ActionData"] as? [[String:Any]] {
self.myNotifications = ActionData
self.generalNotifications = ActionData
//
self.counter.text = "\(ActionData.count)"
self.myNotifications.reverse()
self.myNotificationsTV.reloadData()
self.animationView.isHidden = true
self.animationView.stop()
self.refreshControl.endRefreshing()
}
Also have you noticed that you are doing reverse on your array(generalNotifications.reverse()) whenever you are selecting a cell, which will reverse your array each time. So First time you will get correct value and next time again array will be reversed and wrong value will be returned. Try using reversed array as like below.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let reversedGeneralNotifications = generalNotifications.reversed()
let prepareNum = reversedGeneralNotifications[indexPath.row]["Id"] as? NSNumber
currentBalaghId = Int(prepareNum!)
clickedIndex = indexPath.row
if let text = reversedGeneralNotifications[indexPath.row]["NotifDateG"] as? String {
prepareDateforPassing = text
}
if let text = reversedGeneralNotifications[indexPath.row]["Description"] as? String {
prepareDesciptionforPassing = text
}
if let text = reversedGeneralNotifications[indexPath.row]["TypeName"] as? String {
prepareTypeforPassing = text
}
if let text = reversedGeneralNotifications[indexPath.row]["AddedByName"] as? String {
prepareProviderNameforPassing = text
}
self.performSegue(withIdentifier: "showDetails", sender: self)
// to remove highlighting after finish selecting
tableView.deselectRow(at: indexPath, animated: true)
}
Loading local json file to table view and in Debugger Log all goes fine but data is repeating itself in tableView. I've taken screenshot of simulator and Log both here - May be i think i've a problem in appending data. I have TableViewCell - viewCell and my data class - attendance.swift and a tableViewController of course. I am trying to display two data fields. Code for tableViewController -
var checkins = [attendance]()
override func viewDidLoad() {
super.viewDidLoad()
jsonParsingFromFile()
}
func jsonParsingFromFile()
{
let path: NSString = NSBundle.mainBundle().pathForResource("jsonFile", ofType: "json")!
let data : NSData = try! NSData(contentsOfFile: path as String, options: NSDataReadingOptions.DataReadingMapped)
self.parseJsonData(data)
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}
func parseJsonData(data:NSData) -> [attendance]{
do{
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
//parse json data
let jsonCheckins = jsonResult?["university1"] as! [AnyObject]
for jsonAttendance in jsonCheckins {
let checkin = attendance()
checkin.id = jsonAttendance["id"] as! Int
checkin.name = jsonAttendance["name"] as! String
if (creden != checkin.id)
{
}
else
{
print(checkin.id)
print(checkin.name)
let check = jsonAttendance["attendance"] as! [AnyObject]
for ch in check {
checkin.subject = ch["subject"] as! String
print(checkin.subject)
checkin.attended = ch["attended"] as! Int
checkin.done = ch["held"] as! Int
checkin.atd = (Float(checkin.attended)/Float(checkin.done))*100
print(checkin.atd , " %")
checkins.append(checkin)
}
}
}
}
catch{
print(error)
}
return checkins
}
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 checkins.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! viewCell
cell.subjectLabel.text = checkins[indexPath.row].subject
cell.attendanceLabel.text = String(checkins[indexPath.row].atd)+" %"
return cell
}
Error seems to be because you are updating a single object only and adding it to array. Therefore in the end you are left up with only one type of object in array with same values
let checkin = attendance()
move that to inside the loop
for ch in check {
Hi guys I have been stuck with the error 'array index out of range'. I am getting JSON data from the internet and converting it into an array. I have been loading comments (Note : I have posted this question as i couldnt find any question related to my problem)
So I have been loading comments in a jsonData. The code i've been using to load comments is this.
api.loadComments(shot.commentsUrl, completion: didLoadComments)
The code for completion is this.
func didLoadComments(comments : [Comment]){
self.comments = comments
self.tableView.reloadData()
}
It is defined in the tableView...
let cell = tableView.dequeueReusableCellWithIdentifier("Cell10", forIndexPath: indexPath) as! CommentCell
//This is where the error occurs
let comment = comments[indexPath.row]
cell.nameLabel.text = comment.user.name
cell.commentLabel.text = comment.body
cell.avatarImageView.sd_setImageWithURL(NSURL(string: comment.user.avatarUrl), placeholderImage: UIImage(named: "2"))
return cell
and the comments variable is defined like this.
var comments : [Comment] = Comment
The loadComments method is returning comments as shown in the log
The log which shows comments is not nil
The code for loadComments is this.
func loadComments(commentsUrl: String, completion: (([Comment]) -> Void)!) {
let urlString = commentsUrl + "?access_token=" + Config.ACCESS_TOKEN
let session = NSURLSession.sharedSession()
let url = NSURL(string: urlString)
let task = session.dataTaskWithURL(url!) {
(data, response, error) -> Void in
if error != nil {
print(error!.localizedDescription)
} else {
var comments = [Comment]()
do {
let commentsData = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as! NSArray
for commentData in commentsData {
let comment = Comment(data: commentData as! NSDictionary)
comments.append(comment)
}
}
catch {
}
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
dispatch_async(dispatch_get_main_queue()) {
completion(comments)
}
}
}
task.resume()
}
The numberOfRowsInSection looks like this.
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return 9 + comments.count
}
Feel free to ask me for any more code.
Thanks in advance
Aryan
The reason of that problem is :
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return comments.count
}
This method return your items count. And your method
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell") as! CommentCell
return cell
}
will run in cycle for each item in this list.
You should check items count in method "numberOfRowsInSection" and items count in "cellForRowAtIndexPath"
EDITED :
Of course you did.
return 9 + comments.count
if your comments count will be 0 your fun cellForRowAtIndexPath will call 9 times!!!
Use
comments.count
or add some checks in your code.
Here is how you can proceed with it.
Create a Comment class:
class Comment {
var user: User?
var commentLabel: String?
}
Create a User class:
class User {
var name: String?
var avatarUrl: UIImageView?
}
Then in your for loop parse the Json into Comment object and then add it to comments array:
for commentData in commentsData {
let commentDictionary = Comment(data: commentData as! NSDictionary)
var temp:NSArray = commentDictionary["user"] as! NSArray
var user: User?
user.name = temp["name"]
user.avatarUrl = temp["avatarUrl"]
var comment: Comment?
comment.commentLabel = commentDictionary["body"]
comments.append(comment)
}
This should be it.
Trying to display an array pulled from parse.com in a textview inside of a uitableviewcell. Everything else is showing but I can't seem to get a array to display in a textview. This is the code I have. I'm getting fatal error: Array index out of range for myCell2.feedbacktextview.text = feedback![indexPath.row]
var feedback: [String]?
override func viewDidLoad() {
super.viewDidLoad()
var query = PFQuery(className: "Post")
query.findObjectsInBackgroundWithBlock({ (objects, error) -> Void in
if error == nil {
if let objects = objects {
if object.objectForKey("Comments") != nil {
self.feedback = object.objectForKey("Comments") as! [String]
}
self.tableView.reloadData()
}}}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell2 = tableView.dequeueReusableCellWithIdentifier("feedcell1", forIndexPath: indexPath) as! YourAdviseControllerCell
myCell2.feedbacktextview.text = feedback![indexPath.row]
return myCell2
}
edit:
self.imageFiles.append(object["imageFile1"] as! PFFile)
self.imageFiles2.append(object["imageFile2"] as! PFFile)
self.usernames.append(object["message"] as! String)
self.usernames2.append(object["declaration"] as! String)
self.usernames3.append(object["whichbutton"] as! String)
Basically what you did is intentionally correct but a fair share of small mistakes are left to correct. The takeaway would be never use forced unwrapping when possible.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let myCell2 = tableView.dequeueReusableCellWithIdentifier("feedcell1", forIndexPath: indexPath) as! YourAdviseControllerCell
//This below line fetches the value from feedback if it has else gives ""
myCell2.feedbacktextview.text = feedback?[indexPath.row] ?? ""
return myCell2
}
That would solve the problem for now but i see if this code gets called when then you might be returning some valid values from the numberOfRowsInCells method without respect to the feedback value. Ideally i would do something like this:
var feedback:[String]?
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return feedback?.count ?? 0
}
Even then there is a slight problem i guess. Don't call tableView.reloadData() from a block which is executing in a separate thread or queue. Do all the work in main queue.
if object.objectForKey("Comments") != nil {
self.feedback = object.objectForKey("Comments") as! [String]
}
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
}
Hope it helps! Cheers!