在我的Swift iOS应用程序中,我有一个表视图,它应该显示来自mysql服务器的JSON对象,比如博客阅读器应用程序。但是现在表格视图显示为空,因为当用户单击每行上的按钮移动到另一个部分时,我尝试实现NSUserDefaults来保存。我基本上保存了用户点击的行的indexPath和部分,因此当用户下次打开应用程序时,它会记住它被移动到的位置。但是表格视图显示为空,我不知道如何解决它,希望有人在这里做。谢谢!
ViewController.swift
// Outlets and Variables
@IBOutlet weak var myTableView: UITableView!
let searchController = UISearchController(searchResultsController: nil)
var jsonArray: NSMutableArray = []
var testArray = [Test]()
var followedArray = [Test]()
var filteredArray = [Test]()
// NSUserDefaults
var data: [Any]?
var items: [[Any]]?
override func viewDidLoad() {
super.viewDidLoad()
// Custom Cell
self.myTableView.dataSource = self
self.myTableView.delegate = self
// Load Data from Server
self.retrieveData()
// NSUserDefaults
self.fetchData()
}
// Number of Rows in Section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items?[section].count ?? 0
}
// Number of Sections
func numberOfSections(in tableView: UITableView) -> Int {
return self.items?.count ?? 0
}
// CellForRowAt indexPath
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let CellIdentifier = "Cell"
var cell = tableView.dequeueReusableCell(withIdentifier: CellIdentifier) as! CustomCell
if cell != cell {
cell = CustomCell(style: UITableViewCellStyle.default, reuseIdentifier: CellIdentifier)
}
// Configuring the cell
var testObject: Test
if !(searchController.isActive && searchController.searchBar.text != "") {
if indexPath.section == 0 {
testObject = followedArray[indexPath.row]
cell.populateCell(testObject, isFollowed: true, indexPath: indexPath, parentView: self)
}
else if indexPath.section == 1 {
testObject = testArray[indexPath.row]
cell.populateCell(testObject, isFollowed: false, indexPath: indexPath, parentView: self)
}
}
else {
testObject = filteredArray[indexPath.row]
cell.populateCell(testObject, isFollowed: false, indexPath: indexPath, parentView: self)
}
return cell
}
// Follow Button
@IBAction func followButtonClick(_ sender: UIButton!) {
// Adding row to tag
let buttonPosition = (sender as AnyObject).convert(CGPoint.zero, to: self.myTableView)
if let indexPath = self.myTableView.indexPathForRow(at: buttonPosition) {
let cell = self.myTableView.cellForRow(at: indexPath) as! CustomCell
// Change Follow to Following
(sender as UIButton).setImage(UIImage(named: "follow.png")!, for: .normal)
// Checking wether to import from testArray or filteredArray to followedArray
if !(searchController.isActive && searchController.searchBar.text != "") {
self.myTableView.beginUpdates()
// ----- Inserting Cell to followedArray -----
followedArray.insert(testArray[indexPath.row], at: 0)
myTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .fade)
// ----- Removing Cell from testArray -----
testArray.remove(at: indexPath.row)
let rowToRemove = indexPath.row
self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 1)], with: .fade)
self.myTableView.endUpdates()
// NSUserDefaults
saveSorting() { "\($0)" }
myTableView.reloadData()
}
else {
self.myTableView.beginUpdates()
// ----- Inserting Cell to followedArray -----
let testObject: Test = filteredArray[indexPath.row]
let indexOfObjectInArray = testArray.index(of: testObject)
followedArray.insert(testObject, at: 0)
// ----- Removing Cell from filteredArray -----
filteredArray.remove(at: indexPath.row)
testArray.remove(at: indexOfObjectInArray!)
let rowToRemove = indexPath.row
self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 0)], with: .fade)
self.myTableView.endUpdates()
// NSUserDefaults
saveSorting() { "\($0)" }
myTableView.reloadData()
}
}
}
// Retrieving Data from Server
func retrieveData() {
let getDataURL = "http://exampleip.org/get.php"
let url: NSURL = NSURL(string: getDataURL)!
do {
let data: Data = try Data(contentsOf: url as URL)
jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray
// Looping through jsonArray
for i in 0..<jsonArray.count {
// Create Test Object
let tID: String = (jsonArray[i] as AnyObject).object(forKey: "id") as! String
let tName: String = (jsonArray[i] as AnyObject).object(forKey: "testName") as! String
// Add Test Objects to Test Array
testArray.append(Test(testName: tName, andTestID: tID))
}
}
catch {
print("Error: (Retrieving Data)")
}
myTableView.reloadData()
}
// NSUserDefaults
func fetchData() {
// request from remote or local
data = [testArray]
// Update the items to first section has 0 elements,
// and place all data in section 1
items = [[], data ?? []]
// apply ordering
applySorting() { "\($0)" }
// save ordering
saveSorting() { "\($0)" }
// refresh the table view
myTableView.reloadData()
}
func applySorting(_ dataIdBlock: (Any) -> String) {
// get all saved ordering
guard let data = self.data else { return }
let ordering = DataHandling.allSavedOrdering(data.count)
var result: [[Any]] = [[], []]
for (section, ordering) in ordering {
guard section <= 1 else { continue } // make sure the section is 0 or 1
let rows = data.filter({ obj -> Bool in
return ordering.index(where: { $0.dataId == .some(dataIdBlock(obj)) }) != nil
})
result[section] = rows
}
self.items = result
}
func saveSorting(_ dataIdBlock: (Any) -> String) {
guard let items = self.items else { return }
for (section, rows) in items.enumerated() {
for (row, item) in rows.enumerated() {
let indexPath = IndexPath(row: row, section: section)
let dataId = dataIdBlock(item)
let ordering = DataHandling(dataId: dataId, indexPath: indexPath)
// Warning is here
ordering.save(defaults: indexPath.defaultsKey)
}
}
}
}
extension IndexPath {
var defaultsKey: String {
return "data_handling_\(section)_\(row)"
}
}
CustomCell.swift
class CustomCell: UITableViewCell {
func populateCell(_ testObject: Test, isFollowed: Bool, indexPath: IndexPath, parentView: Any) {
if isFollowed {
self.followedButton.tag = indexPath.row
self.followedButton.addTarget(parentView, action: #selector(ViewController.followedButtonClick(_:)), for: .touchUpInside)
self.followedButton.isHidden = false
self.followButton.isHidden = true
}
else {
self.followButton.tag = indexPath.row
self.followButton.addTarget(parentView, action: #selector(ViewController.followButtonClick(_:)), for: .touchUpInside)
self.followedButton.isHidden = true
self.followButton.isHidden = false
}
}
}
DataHandling.swift 处理NSUserDefault
class DataHandling: NSObject, NSCoding {
var indexPath: IndexPath?
var dataId: String?
init(dataId: String, indexPath: IndexPath) {
super.init()
self.dataId = dataId
self.indexPath = indexPath
}
required init(coder aDecoder: NSCoder) {
if let dataId = aDecoder.decodeObject(forKey: "dataId") as? String {
self.dataId = dataId
}
if let indexPath = aDecoder.decodeObject(forKey: "indexPath") as? IndexPath {
self.indexPath = indexPath
}
}
func encode(with aCoder: NSCoder) {
aCoder.encode(dataId, forKey: "dataId")
aCoder.encode(indexPath, forKey: "indexPath")
}
func save(defaults box: String) -> Bool {
let defaults = UserDefaults.standard
let savedData = NSKeyedArchiver.archivedData(withRootObject: self)
defaults.set(savedData, forKey: box)
return defaults.synchronize()
}
convenience init?(defaults box: String) {
let defaults = UserDefaults.standard
if let data = defaults.object(forKey: box) as? Data,
let obj = NSKeyedUnarchiver.unarchiveObject(with: data) as? DataHandling,
let dataId = obj.dataId,
let indexPath = obj.indexPath {
self.init(dataId: dataId, indexPath: indexPath)
} else {
return nil
}
}
class func allSavedOrdering(_ maxRows: Int) -> [Int: [DataHandling]] {
var result: [Int: [DataHandling]] = [:]
for section in 0...1 {
var rows: [DataHandling] = []
for row in 0..<maxRows {
let indexPath = IndexPath(row: row, section: section)
if let ordering = DataHandling(defaults: indexPath.defaultsKey) {
rows.append(ordering)
}
rows.sort(by: { $0.indexPath! < $1.indexPath! })
}
result[section] = rows
}
return result
}
}