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)
}
Related
I am trying to populate a UITableView using an array and I am unable to do so. Here is what I have so far. This code is for retrieving data and storing it in the array that I am using to populate the UITableView:
func prepareForRetrieval() {
Database.database().reference().child("UserCart").child(Auth.auth().currentUser!.uid).observe(.value, with: {
(snapshot) in
for snap in snapshot.children.allObjects {
let id = snap as! DataSnapshot
self.keyArray.append(id.key)
}
self.updateCart()
})
}
func updateCart() {
for key in keyArray {
Database.database().reference().child("UserCart").child(Auth.auth().currentUser!.uid).child(key).observeSingleEvent(of: .value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let itemName = value?["Item Name"] as! String
let itemPrice = value?["Item Price"] as! Float
let itemQuantity = value?["Item Quantity"] as! Int
self.cartArray.append(CartData(itemName: itemName, itemQuantity: itemQuantity, itemPriceNumber: itemPrice))
print(self.cartArray.count)
})
}
}
The data is properly appending into the array and when I print the count of the array, it prints the correct count. This means that the data is there. However, when I try to populate a UITableView, it doesn't detect any data. I have the following code to make sure that there is data in the array before trying to populate the UITableView:
override func viewDidLoad() {
super.viewDidLoad()
cartBrain.prepareForRetrieval()
if cartBrain.cartArray.isEmpty == false{
tableViewOutlet.dataSource = self
tableViewOutlet.reloadData()
}
else {
tableViewOutlet.isHidden = true
tableViewOutlet.isUserInteractionEnabled = false
purchaseButtonOutlet.isEnabled = false
cartEmptyLabel.text = "Your cart is empty. Please add items and check back later."
}
}
When I open the View Controller, the TableView is disabled because it doesn't detect any data. I have already set the data source to self and the thing is that when the count of the array is printed, it again prints the correct amount. I have already set the data source to self for the UITableView. Here is my code for the UITableView:
extension CartViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cartBrain.cartArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cartcustomcell", for: indexPath)
cell.textLabel?.text = cartBrain.cartArray[indexPath.row].itemName
cell.detailTextLabel?.text = String(cartBrain.cartArray[indexPath.row].itemQuantity)
return cell
}
}
I don't understand why the count of the array prints the correct amount meaning that there is data stored in it but when the View Controller is loaded, it detects that the array is empty. Thanks for the help and I'm sorry if the question is a bit unclear.
After appending data to cartArray in updateCart you should reloadData(), like this:
weak var tableViewOutlet: UITableView?
func updateCart() {
for key in keyArray {
Database.database().reference().child("UserCart").child(Auth.auth().currentUser!.uid).child(key).observeSingleEvent(of: .value, with: {
(snapshot) in
let value = snapshot.value as? NSDictionary
let itemName = value?["Item Name"] as! String
let itemPrice = value?["Item Price"] as! Float
let itemQuantity = value?["Item Quantity"] as! Int
self.cartArray.append(CartData(itemName: itemName, itemQuantity: itemQuantity, itemPriceNumber: itemPrice))
DispatchQueue.main.async {
self.tableViewOutlet.reloadData()
}
})
}
}
The updateCart doesn't seem to have any connection to the tableViewOutlet so you need to pass in a reference to it in your viewDidLoad like this:
override func viewDidLoad() {
super.viewDidLoad()
cartBrain.tableViewOutlet = tableViewOutlet
cartBrain.prepareForRetrieval()
Note: Since you're using a for loop to trigger the async call multiple times you can use the array count to check if all the items are appended to do the reload to avoid multiple reloads.
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.
This is my code —- I am getting error when returning cell1 inside the if statement as it says ” Cannot return a non void return value in void function.I want to return the cell in tableview .. and i have 3 kind of posts .. one for status one for image one for video post. How can i return the cell for each.
P.S. : I have just provided the code for one post type only as if one is solved then all other can be solved.
import UIKit
import Alamofire
class ViewController: UIViewController , UITableViewDelegate ,
UITableViewDataSource{
#IBOutlet weak var feedTable: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
feedTable.dataSource = self
feedTable.delegate = self
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 5
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 376
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
Alamofire.request("https://new.postpfgsdfdsgshfghjoves.com/api/posts/get_all_posts").responseJSON { response in
let result = response.result
if let dict = result.value as? Dictionary<String,AnyObject> {
if let successcode = dict["STATUS_CODE"] as? Int {
if successcode == 1 {
if let postsArray = dict["posts"] as? [Dictionary<String,AnyObject>]
{
for i in 0..<postsArray.count
{
let posttype = postsArray[i]["media_type"] as! String
if posttype == "image"
{
let cell1 : ImageTableViewCell = self.feedTable.dequeueReusableCell(withIdentifier: "imageReuse") as! ImageTableViewCell
cell1.fullName = postsArray[i]["full_name"] as? String
cell1.profileImageURL = postsArray[i]["profile_pic"] as? String
cell1.location = postsArray[i]["location"] as? String
cell1.title = postsArray[i]["title"] as? String
cell1.postTime = postsArray[i]["order_by_date"] as? String
cell1.likes = postsArray[i]["liked_count"] as? Int
cell1.comments = postsArray[i]["comment_count"] as? Int
cell1.imageURL = postsArray[i]["profile_pic"] as? String
cell1.imageLocation = postsArray[i]["location"] as? String
cell1.content = postsArray[i]["content"] as? String
cell1.profileFullName.text = cell1.fullName
cell1.titleImagePost.text = cell1.title
cell1.postLocation.text = cell1.location
cell1.profileUserLocation.text = cell1.location
cell1.numberOfLikes.text = "\(cell1.likes!) Likes"
cell1.numberOfComments.text = "\(cell1.comments!) Comments"
cell1.postTimeOutlet.text = postsArray[i]["posted_on"] as? String
let url = URL(string: cell1.imageURL!)
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell1.profileImage.image = UIImage(data: data!)
let url1 = URL(string: cell1.imageURL!)
let data1 = try? Data(contentsOf: url1!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell1.postedImage.image = UIImage(data: data1!)
// return cell1
}
else if posttype == "status"
{
let cell1 : StatusTableViewCell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: "statusReuse") as! StatusTableViewCell
cell1.fullName = postsArray[i]["full_name"] as? String
cell1.profileImageURL = postsArray[i]["profile_pic"] as? String
cell1.location = postsArray[i]["location"] as? String
cell1.title = postsArray[i]["title"] as? String
cell1.postTime = postsArray[i]["order_by_date"] as? String
cell1.likes = postsArray[i]["liked_count"] as? Int
cell1.comments = postsArray[i]["comment_count"] as? Int
cell1.postContent = postsArray[i]["content"] as? String
cell1.profileFullName.text = cell1.fullName
cell1.titleStatusPost.text = cell1.title
cell1.postLocation.text = cell1.location
cell1.profileUserLocation.text = cell1.location
cell1.content.text = cell1.postContent
cell1.numberOfLikes.text = "\(cell1.likes!) Likes"
cell1.numberOfComments.text = "\(cell1.comments!) Comments"
cell1.postTimeOutlet.text = "\(cell1.postTime!)"
let url = URL(string: cell1.profileImageURL!)
let data = try? Data(contentsOf: url!) //make sure your image in this url does exist, otherwise unwrap in a if let check / try-catch
cell1.profileImage.image = UIImage(data: data!)
// return cell1
}
else if posttype == "video"
{
let cell1 : VideoTableViewCell = self.feedTable.dequeueReusableCell(withIdentifier: "videoReuse") as! VideoTableViewCell
cell1.fullName = postsArray[i]["full_name"] as? String
// cell1.profession = postsArray[i]["profession"] as? String
cell1.profileImageURL = postsArray[i]["profile_pic"] as? String
cell1.location = postsArray[i]["location"] as? String
cell1.title = postsArray[i]["title"] as? String
cell1.postTime = postsArray[i]["order_by_date"] as? String
cell1.likes = postsArray[i]["liked_count"] as? Int
cell1.comments = postsArray[i]["comment_count"] as? Int
cell1.videoURL = postsArray[i]["profile_pic"] as? String
cell1.profileFullName.text = cell1.fullName
cell1.titleVideoPost.text = cell1.title
cell1.postLocation.text = cell1.location
cell1.profileUserLocation.text = cell1.location
// return cell1
}
}
}
}
}
}
}
}
}
My answer isn't any different from the others but let me be a little more specific. I'll use a generic example and you'll need to tailor this to your specific needs.
1) Define a model somewhere for your data such as:
class MyDataItem {
var name: String
var title: String
var location: String
init(name: String, title: String, location: String) {
self.name = name
self.title = title
self.location = location
}
}
2) Define an array in your Viewcontroller such as:
var dataArray = [MyDataItem]()
3) Load the data which you could do from the viewDidLoad method:
override func viewDidLoad() {
super.viewDidLoad()
feedTable.dataSource = self
feedTable.delegate = self
loadData()
}
4) Implement loadData() function:
func loadData() {
// Here put in your alamo enclosure to retrieve the data and store it into the array you've defined
// When done, call reload data
feedTable.reloadData()
}
5) Your cellForRowAt function will need to be modified to retrieve the data from the array. For example:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell1 : ImageTableViewCell = tableView.dequeueReusableCell(withIdentifier: "imageReuse") as! ImageTableViewCell
cell1.fullName = dataArray[indexPath.row].name
cell1.title = dataArray[indexPath.row].title
cell1.location = dataArray[indexPath.row].location
return cell1
}
Anyway, this is the general idea on how to do what you are attempting. When reloadData is called from your loadData function, it will cause the tableview to reload from the array data correctly.
Hope this helps!
The problem is you do not return the cell, you simply make some async request with alamofire and return an instance of the cell from the closure.
func foo() -> Int { return 1 } ≠ func bar() -> Int { someClosure { return 1 } }
Firstly you need load the the data from https://www.example.com/api/posts/get_all_posts into some data model.
var models: [SomeTypeYouCreate] = []
func loadData() {
Alamofire.request(...).responseJSON { response in
self.models = /* Create array of `SomeTypeYouCreate` objects from response */
self.tableView.reloadData()
}
}
func func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let model = self.models[indexPath.row]
// configure cell with model
return cell
}
You cannot do it the way you're trying to. You're not returning a cell from cellForRowAt method, you're returning it in Alamofire callback closure. What you should do is to return the cell in your cellForRowAt method, and implement some sort of setup method for your UITableViewCell subclass and make your calls in there
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell1 : ImageTableViewCell = self.feedTable.dequeueReusableCell(withIdentifier: "imageReuse") as! ImageTableViewCell
// put your Alamofire code inside such function in your UITableViewCell subclass
cell.setup()
return cell
}
First and foremost, you are returning value in closure Alamofire.request. If you wanna use cell after you confirm cell values, you want to pass over completion handler to the function and use it in that Alamofire.reqeust...
But if I were you, I would create another function which is called before/after tableView function.
If it is Before then trigger tableview initialization upon alamofire completion.
If it is After then reload when values are loaded correctly in Alamofire.
EDITED:
Like other suggested,it is bad idea to load data in tableView function. Also, by using Alamofire, it means you use Closure. That is, whatever you wanna do in Alamofire happens asynchronously, meaning by the time what you want to achieve in Alamofire is done, your program can be out of the table view function. Also, since it is closure, returning value in Alamofire does not satisfy your tableView return type.
So basically, if you need data via API and verify, you declare function such that do whatever you doing Alamofire and then reload the tableView.
So flow is like this:
1) Make an empty array and put array.count to # of rows.
2) Since it is empty, when tableView first try to generate cells, it doesn't do anything.
3) You call the function which uses Alamofire. If returned values are good, then add the cell(model) to the array.
4) After you are done loading models, do tableView.reload().
5) Tableview calls tableView function now it finds value in array so that will create cells.
I tried to reload my UITableView after adding new items. When I try with a reloadData() it's not working. Nothing is shown.
If I try to reload my getallrecords function, that reload items but they are repeated.
My source code is :
class FriendsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, DZNEmptyDataSetSource, DZNEmptyDataSetDelegate {
#IBOutlet var tabeview: UITableView!
var textArray: NSMutableArray! = NSMutableArray()
var subArray: NSMutableArray! = NSMutableArray()
let defaults = NSUserDefaults.standardUserDefaults()
var valueToPass:String!
var reports_d:String!
var reports:String!
#IBOutlet var menuButton: UIBarButtonItem!
#IBOutlet var friends_icon: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
tabeview.dataSource = self
tabeview.delegate = self
tabeview.emptyDataSetSource = self
tabeview.emptyDataSetDelegate = self
tabeview.tableFooterView = UIView()
getallrecords()
self.tabeview.addPullToRefresh({ [weak self] in
// refresh code
self!.getallrecords()
self?.tabeview.stopPullToRefresh()
})
// Do any additional setup after loading the view.
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.textArray.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell")
cell.textLabel?.text = self.textArray.objectAtIndex(indexPath.row) as? String
cell.detailTextLabel?.text = self.subArray.objectAtIndex(indexPath.row) as? String
return cell
}
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
print("You selected cell #\(indexPath.row)!")
// Get Cell Label
let indexPath = tableView.indexPathForSelectedRow!
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
valueToPass = currentCell.textLabel!.text
reports = reports_d
performSegueWithIdentifier("friends_details", sender: self)
}
func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
return true
}
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from your array and updating the tableview)
let currentCell = tableView.cellForRowAtIndexPath(indexPath)! as UITableViewCell
let friend2 = currentCell.textLabel!.text
let defaults = NSUserDefaults.standardUserDefaults()
let username = defaults.objectForKey("name") as! String
Alamofire.request(.GET, "http://www.example.com/app/remove_friends.php", parameters: ["key_id": "xxxxx","user_id": username,"friend_receive_id": friend2!, "action": "delete"])
.response { request, response, data, error in
print(request)
print(response)
print(error)
if(error == nil)
{
self.tabeview.beginUpdates()
self.textArray.removeObjectAtIndex(indexPath.row)
self.subArray.removeObjectAtIndex(indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
self.tabeview.endUpdates()
}
}
NSNotificationCenter.defaultCenter().postNotificationName("reloadData",object: self)
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?){
if (segue.identifier == "friends_details") {
// initialize new view controller and cast it as your view controller
let viewController = segue.destinationViewController as! DetailsFriendsViewController
// your new view controller should have property that will store passed value
viewController.passedValue = valueToPass
viewController.reports = reports
}
}
func getallrecords(){
if(defaults.stringForKey("name") != nil ){
let username = defaults.objectForKey("name") as! String
let full = "http://www.example.com/app/danger_friend_view.php?search=true&username=" + username
let url = NSURL(string: full)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
do {
let d = NSString(data: data!, encoding: NSUTF8StringEncoding)
var arr = d!.componentsSeparatedByString("<") // spliting the incoming string from "<" operator because before that operator is our required data and storing in array
let dataweneed:NSString = arr[0] as NSString // arr[0] is the data before "<" operator and arr[1] is actually no use for us
NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
SwiftSpinner.hide()
do {
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
self.textArray.addObject(info)
self.subArray.addObject(name)
}
self.tabeview.reloadData()
}
} catch let error as NSError {
print(error.localizedDescription)
}
})
}
}
task.resume()
}
else
{
//Do something
}
}
#IBAction func reload_data(sender: UIButton) {
let banner = Banner(title: NSLocalizedString("RELOAD_DATA_TITLE",comment:"I'm in danger, I'm currently at "), subtitle: NSLocalizedString("RELOAD_DATA",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:52.00/255.0, green:152.00/255.0, blue:219.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
dispatch_async(dispatch_get_main_queue()) {
//Not working ....
self.tabeview.reloadData()
}
}
func titleForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let str = "Oups"
let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)]
return NSAttributedString(string: str, attributes: attrs)
}
func descriptionForEmptyDataSet(scrollView: UIScrollView!) -> NSAttributedString! {
let str = NSLocalizedString("NO_FRIENDS_TO_SHOW",comment:"No friends to show ")
let attrs = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleBody)]
return NSAttributedString(string: str, attributes: attrs)
}
func imageForEmptyDataSet(scrollView: UIScrollView!) -> UIImage! {
return UIImage(named: "no-friends")
}
func buttonTitleForEmptyDataSet(scrollView: UIScrollView!, forState state: UIControlState) -> NSAttributedString! {
let str = NSLocalizedString("ADD_FRIENDS",comment:"Add a friend ")
let attrs = [NSFontAttributeName: UIFont(name: "HelveticaNeue-Light", size: 19)!]
return NSAttributedString(string: str, attributes: attrs)
}
func emptyDataSetDidTapButton(scrollView: UIScrollView!) {
let alert = SCLAlertView()
let txt = alert.addTextField("Friend's username")
alert.addButton("Add") {
if(txt.text=="")
{
let banner = Banner(title: NSLocalizedString("ERROR_NO",comment:"An error occured"), subtitle: NSLocalizedString("ERROR_NO_TEXT",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:152.00/255.0, green:52.00/255.0, blue:52.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
}
else
{
let defaults = NSUserDefaults.standardUserDefaults()
let username = defaults.objectForKey("name") as! String
let remove_friend_username = txt.text! as String
Alamofire.request(.GET, "http://www.example.com/add_friends.php", parameters: ["key_id": "xxx","user_id": username,"friend_receive_id": remove_friend_username, "action": "add"])
.response { request, response, data, error in
dispatch_async(dispatch_get_main_queue()) {
self.tabeview.reloadData()
//Not working
}
}
}
}
alert.showEdit("Add friend", subTitle: "You can add a friend by enter his username")
}
}
I believe you are missing a little point in here buddy :)
Question 1
Why reloading tableView wont show new data ??
Your function reload_data is doing nothing more than reloading data buddy :) When you call reload data all the tableView delegates like number of rows in section,number of sections and cellForRowAtIndexPath gets called but all these methods return the value depending on the data source you provide isn't it buddy :)
So if you change the data source and then call reload data they will show you the new data :) but in your reload_data function you are not altering the data source at all :) simply calling reload data on the unalterred data source will re render the tableView again thats all :)
What you can do :)
You already have a method that fetches the new data using almofire :) just call it and in the success block anyway you are reloading the tableView :) So everything will be fine buddy :)
#IBAction func reload_data(sender: UIButton) {
let banner = Banner(title: NSLocalizedString("RELOAD_DATA_TITLE",comment:"I'm in danger, I'm currently at "), subtitle: NSLocalizedString("RELOAD_DATA",comment:"I'm in danger, I'm currently at "), image: UIImage(named: "Icon"), backgroundColor: UIColor(red:52.00/255.0, green:152.00/255.0, blue:219.00/255.0, alpha:0.89))
banner.dismissesOnTap = true
banner.show(duration: 10.0)
self.getallrecords() //simply call this method this will anyhow will reload data on success :)
}
Question 2
Why my tableView shows duplicate data???
Your tableView always show the data which is there in its datasource :) SO if your tableView is showing duplicate cells that means you have duplicate entry in your data source :)
You are dealing with array, in future you might migrate to coredata :)
Understand one thing, when you enter or add a entry to your data source if you dont want to show duplicates you will have to handle it explicitly.
How can I do that ???
From your code I beilieve info(username) value is unique per object. So before blindly adding response to textArray check if text array already consists that object if yes then dont add it again :)
Based on the above stated assumption and believing you are making use of swift 2.0
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
if !self.textArray.contains(info){
self.textArray.addObject(info)
self.subArray.addObject(name)
}
}
self.tabeview.reloadData()
}
Now that's a lot of code, I want a easier solution :)
Clear the array before adding the new response :) Thats all :)
if let data = try NSJSONSerialization.JSONObjectWithData(dataweneed.dataUsingEncoding(NSUTF8StringEncoding)!, options: [NSJSONReadingOptions.MutableContainers]) as? NSArray {
self.textArray.removeAll()
self.subArray.removeAll() //clear the arrays and then re populate them thats all no duplicate data anymore :P
for dd in data{
var name : String = dd["danger"]! as! String
self.reports_d = name
let info : String = dd["username"]! as! String
name = NSLocalizedString("SEND_ALERT_BEGIN",comment:"SEND_ALERT") + name + NSLocalizedString("ALERTS",comment:"ALERTS")
print("ID is : \(name)")
print("Username is : \(info)")
self.textArray.addObject(info)
self.subArray.addObject(name)
}
self.tabeview.reloadData()
}
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 :)