ReloadData 无法与 Alamofire 一起工作 Swift
ReloadData not working Swift with Alamofire
我尝试在添加新项目后重新加载 UITableView
。当我尝试使用 reloadData()
时,它不起作用。什么都没有显示。
如果我尝试重新加载我的 getallrecords
函数,那会重新加载项目但它们会重复。
我的源代码是:
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")
}
}
我相信你在这里遗漏了一点点,伙计:)
问题 1
为什么重新加载 tableView 不会显示新数据??
你的函数 reload_data 只不过是重新加载数据伙伴 :) 当你调用重新加载数据时,所有 tableView 委托都会调用部分中的行数、部分数和 cellForRowAtIndexPath,但所有这些方法 return这个值取决于你提供的数据源是不是哥们:)
因此,如果您更改数据源然后调用 reload data,它们将向您显示新数据 :) 但在您的 reload_data 函数中,您根本没有更改数据源 :) 只需调用 reload data在未更改的数据源上将再次重新呈现 tableView,仅此而已:)
你能做什么:)
你已经有了一个使用 almofire 获取新数据的方法 :) 只需调用它,无论如何你都在成功块中重新加载 tableView :) 所以一切都会好起来的伙计 :)
@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 :)
}
问题 2
为什么我的tableView显示重复的数据???
您的 tableView 始终显示其数据源中的数据 :) 因此,如果您的 tableView 显示重复的单元格,则意味着您的数据源中有重复条目 :)
您正在处理数组,将来您可能会迁移到 coredata :)
了解一件事,当您在数据源中输入或添加条目时,如果您不想显示重复项,则必须明确处理它。
我该怎么做???
根据您的代码,我相信每个对象的信息(用户名)值都是唯一的。因此,在盲目地向 textArray 添加响应之前,检查文本数组是否已经包含该对象,如果是,则不要再次添加它:)
基于上述假设并相信您正在使用 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()
}
现在有很多代码,我想要一个更简单的解决方案:)
在添加新响应之前清除数组 :) 仅此而已 :)
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()
}
我尝试在添加新项目后重新加载 UITableView
。当我尝试使用 reloadData()
时,它不起作用。什么都没有显示。
如果我尝试重新加载我的 getallrecords
函数,那会重新加载项目但它们会重复。
我的源代码是:
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")
}
}
我相信你在这里遗漏了一点点,伙计:)
问题 1 为什么重新加载 tableView 不会显示新数据??
你的函数 reload_data 只不过是重新加载数据伙伴 :) 当你调用重新加载数据时,所有 tableView 委托都会调用部分中的行数、部分数和 cellForRowAtIndexPath,但所有这些方法 return这个值取决于你提供的数据源是不是哥们:)
因此,如果您更改数据源然后调用 reload data,它们将向您显示新数据 :) 但在您的 reload_data 函数中,您根本没有更改数据源 :) 只需调用 reload data在未更改的数据源上将再次重新呈现 tableView,仅此而已:)
你能做什么:)
你已经有了一个使用 almofire 获取新数据的方法 :) 只需调用它,无论如何你都在成功块中重新加载 tableView :) 所以一切都会好起来的伙计 :)
@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 :)
}
问题 2 为什么我的tableView显示重复的数据???
您的 tableView 始终显示其数据源中的数据 :) 因此,如果您的 tableView 显示重复的单元格,则意味着您的数据源中有重复条目 :)
您正在处理数组,将来您可能会迁移到 coredata :) 了解一件事,当您在数据源中输入或添加条目时,如果您不想显示重复项,则必须明确处理它。
我该怎么做???
根据您的代码,我相信每个对象的信息(用户名)值都是唯一的。因此,在盲目地向 textArray 添加响应之前,检查文本数组是否已经包含该对象,如果是,则不要再次添加它:)
基于上述假设并相信您正在使用 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()
}
现在有很多代码,我想要一个更简单的解决方案:)
在添加新响应之前清除数组 :) 仅此而已 :)
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()
}