Swift:如何从我的表格视图中删除重复项?

Posted

技术标签:

【中文标题】Swift:如何从我的表格视图中删除重复项?【英文标题】:Swift: How to remove duplicates from my table view? 【发布时间】:2017-06-15 19:25:51 【问题描述】:

这里的问题是我的表格视图中有重复项,我知道原因,但我不知道如何修复它并实施不同的系统。

我的应用程序是一个博客阅读器,它使用 phpmysql 数据库中读取数据,以将 JSON 发送到我的 Swift 应用程序。我的表格视图有两个部分,一个用于数据库中的所有对象,第二个部分用于当我单击单元格上的跟随按钮时,基本上将对象从 mainArray 移动到 followArray。每个部分都使用一个数组,因此例如我将所有对象从 mainArray 移动到 followArray 并更新表我再次在 mainArray 中获取所有这些对象,显然是因为 mainarray 是空的并且代码只是在做它的工作。

那么我怎样才能实现一个更好的系统,这样当用户将对象从一个部分移动到另一个部分(或从 mainArray 到 followArray)时,mainArray 不会重新填充它拥有的相同对象,现在在 followArray 中。

这是我使用的代码。

MainController.swift - Tableview 所在的类

var mainArray = [Blog]()
var followedArray = [Blog]()

// Title for Header
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? 

    if !(searchController.isActive && searchController.searchBar.text != "") 

        if section == 0 
            return "Followed Blogs"
        
        else 
            return "All Blogs"
        
    
    return "Filtered Blogs"


// Number of Rows in Section
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 

    if !(searchController.isActive && searchController.searchBar.text != "") 

        if section == 0 

            return followedArray.count
        
        else if (section == 1) 

            return mainArray.count
        
    
    return filteredArray.count


// 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 blogObject: Blog

    if !(searchController.isActive && searchController.searchBar.text != "") 
        if indexPath.section == 0 
            blogObject = followedArray[indexPath.row] 
            cell.populateCell(blogObject, isFollowed: true, indexPath: indexPath, parentView: self)
        
        else if indexPath.section == 1 
            blogObject = mainArray[indexPath.row] 
            cell.populateCell(blogObject, isFollowed: false, indexPath: indexPath, parentView: self)
        
    
    else 
        blogObject = filteredArray[indexPath.row] 
        cell.populateCell(blogObject, 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) 

        // Showing Status Labels
        let cell = self.myTableView.cellForRow(at: indexPath) as! CustomCell
        cell.firstStatusLabel.isHidden = false
        cell.secondStatusLabel.isHidden = false

        // Change Follow to Following
        (sender as UIButton).setImage(UIImage(named: "follow.png")!, for: .normal)
        cell.followButton.isHidden = true
        cell.followedButton.isHidden = false

        // Checking wether to import from mainArray or filteredArray to followedArray
        if !(searchController.isActive && searchController.searchBar.text != "") 

            self.myTableView.beginUpdates()

            // ----- Inserting Cell to followedArray -----
            followedArray.insert(mainArray[indexPath.row], at: 0)
            myTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .fade)

            // ----- Removing Cell from mainArray -----
            mainArray.remove(at: indexPath.row)
            let rowToRemove = indexPath.row
            self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 1)], with: .fade)

            self.myTableView.endUpdates()

            myTableView.reloadData()

            // After Updating Table, Save the Archived to UserDefaults
            saveUserDefaults()
        
        else 

            self.myTableView.beginUpdates()

            // ----- Inserting Cell to followedArray -----
            let blogObject: Blog = filteredArray[indexPath.row]
            let indexOfObjectInArray = mainArray.index(of: blogObject)

            followedArray.insert(blogObject, at: 0)

            // ----- Removing Cell from filteredArray -----
            filteredArray.remove(at: indexPath.row)
            mainArray.remove(at: indexOfObjectInArray!)
            let rowToRemove = indexPath.row
            self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 0)], with: .fade)

            self.myTableView.endUpdates()

            myTableView.reloadData()

            // After Updating Table, Save the Archived to UserDefaults
            saveUserDefaults()
        
    



// Retrieving Data from Server
func retrieveDataFromServer() 

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    do 
        let data: Data = try Data(contentsOf: url as URL)
        let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

        // Looping through jsonArray
        for jsonObject in jsonArray 

            if let blog = Blog.createGame(from: jsonObject as AnyObject) 

                mainArray.append(blog)
            
        
    
    catch 
        print("Error: (Retrieving Data)")
    
    myTableView.reloadData()

Blog.swift - 处理我也使用 NSCoder 的博客对象

import UIKit

class Blog: NSObject, NSCoding 

var blogName: String!
var blogStatus1: String!
var blogStatus2: String!
var blogURL: String!
var blogID: String!
var blogType: String!
var blogDate: String!
var blogPop: String!

static func createBlog(from jsonObject: AnyObject) -> Blog? 

    guard let bID: String = jsonObject.object(forKey: "id") as? String,
        let bName: String = jsonObject.object(forKey: "blogName") as? String,
        let bStatus1: String = jsonObject.object(forKey: "blogStatus1") as? String,
        let bStatus2: String = jsonObject.object(forKey: "blogStatus2") as? String,
        let bURL: String = jsonObject.object(forKey: "blogURL") as? String,
        let bType: String = jsonObject.object(forKey: "blogType") as? String,
        let bDate: String = jsonObject.object(forKey: "blogDate") as? String,
        let bPop: String = jsonObject.object(forKey: "blogPop") as? String

        else 
          print("Error: (Creating Blog Object)")
          return nil


let blog = Blog()
    blog.blogName = bName
    blog.blogStatus1 = bStatus1
    blog.blogStatus2 = bStatus2
    blog.blogURL = bURL
    blog.blogID = bID
    blog.blogType = bType
    blog.blogDate = bDate
    blog.blogPop = bPop
    return blog


convenience required init?(coder aDecoder: NSCoder) 
    self.init ()
    self.blogName = aDecoder.decodeObject(forKey: "blogName") as! String
    self.blogStatus1 = aDecoder.decodeObject(forKey: "blogStatus1") as! String
    self.blogStatus2 = aDecoder.decodeObject(forKey: "blogStatus2") as! String
    self.blogURL = aDecoder.decodeObject(forKey: "blogURL") as! String
    self.blogID = aDecoder.decodeObject(forKey: "blogID") as! String
    self.blogType = aDecoder.decodeObject(forKey: "blogType") as! String
    self.blogDate = aDecoder.decodeObject(forKey: "blogDate") as! String
    self.blogPop = aDecoder.decodeObject(forKey: "blogPop") as! String


func encode(with aCoder: NSCoder) 
    aCoder.encode(blogName, forKey: "blogName")
    aCoder.encode(blogStatus1, forKey: "blogStatus1")
    aCoder.encode(blogStatus2, forKey: "blogStatus2")
    aCoder.encode(blogURL, forKey: "blogURL")
    aCoder.encode(blogID, forKey: "blogID")
    aCoder.encode(blogType, forKey: "blogType")
    aCoder.encode(blogDate, forKey: "blogDate")
    aCoder.encode(blogPop, forKey: "blogPop")
 

有没有办法在重新填充 mainArray 之前进行检查,以查看 followArray 中的内容以及丢失或添加到数据库中的任何内容以导入并且不创建重复项,因为将添加新博客并且用户将跨部分转移博客,所以这是一个我遇到的主要问题。

感谢您的帮助,因为我还在学习 Swift,谢谢。

【问题讨论】:

表格视图的模型类是什么?已经存在于模型类中,我们不应该有任何重复。 对象从mainArray转移到followdArray后,mainArray为空,因此重新填充 您是否想在使用应用程序之间保存“关注的博客列表”? 是的,还有 mainArray,因为那是最初所有对象所在的位置,也是添加它们的位置 【参考方案1】:

我建议将应属于以下类别的博客的唯一标识符保存到数组中,并在每次重新加载 tableView 时,将正确的单元格移动到正确的部分。

您似乎正在使用UserDefaults,但没有对其进行任何修改。使用我的方法,唯一需要保存到 UserDefaults 并从中加载的数组是关注的博客列表。其余默认为主列表,即使出现新博客也是如此。

你还需要一个数组:

var mainArray = [Blog]()
var followedArray = [Blog]()
var followedIdentifiers = [String]()

或标识符将采用的任何数据类型

您也可以使用Set,因为您不希望在 followIdentifiers 中出现重复项

var followedIdentifiers = Set<String>()

以下是对代码相关部分的修改(我的更改标记为&lt;----):

// Checking whether to import from mainArray or filteredArray to followedArray
if !(searchController.isActive && searchController.searchBar.text != "") 

    self.myTableView.beginUpdates()

    // Save identifier into followedIdentifier array <--------------
    self.followedIdentifiers.insert(mainArray[indexPath.row].blogID)

    // ----- Inserting Cell to followedArray -----
    followedArray.insert(mainArray[indexPath.row], at: 0)
    myTableView.insertRows(at: [IndexPath(row: 0, section: 0)], with: .fade)

    // ----- Removing Cell from mainArray -----
    mainArray.remove(at: indexPath.row)
    let rowToRemove = indexPath.row
    self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 1)], with: .fade)

    self.myTableView.endUpdates()

    myTableView.reloadData()

    // After Updating Table, Save the Archived to UserDefaults
    saveUserDefaults()
 else 

    self.myTableView.beginUpdates()

    // Remove identifier into followedIdentifier array <------------
    self.followedIdentifiers.remove(followedArray[indexPath.row].blogID)

    // ----- Inserting Cell to followedArray -----
    let blogObject: Blog = filteredArray[indexPath.row]
    let indexOfObjectInArray = mainArray.index(of: blogObject)

    followedArray.insert(blogObject, at: 0)

    // ----- Removing Cell from filteredArray -----
    filteredArray.remove(at: indexPath.row)
    mainArray.remove(at: indexOfObjectInArray!)
    let rowToRemove = indexPath.row
    self.myTableView.deleteRows(at: [IndexPath(row: rowToRemove, section: 0)], with: .fade)

    self.myTableView.endUpdates()

    myTableView.reloadData()

    // After Updating Table, Save the Archived to UserDefaults
    saveUserDefaults()


// Retrieving Data from Server
func retrieveDataFromServer() 

    let getDataURL = "http://example.com/receiving.php"
    let url: NSURL = NSURL(string: getDataURL)!

    do 
        let data: Data = try Data(contentsOf: url as URL)
        let jsonArray = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as! NSMutableArray

        // Clear the arrays      <-------------
        self.followedArray = [Blog]()
        self.mainArray = [Blog()]

        // Looping through jsonArray
        for jsonObject in jsonArray 

            if let blog = Blog.createBlog(from: jsonObject as AnyObject) 
                // Check if identifiers match <------------
                if followedIdentifiers.contains(blog.blogID) 
                    self.followedArray.append(blog)
                 else 
                    self.mainArray.append(blog)
                

            
        
     catch 
        print("Error: (Retrieving Data)")
    
    myTableView.reloadData()

为了使其跨会话起作用,您的saveUserDefaults()中必须有与此类似的内容

UserDefaults.standard.setValue(Array(self.followedIdentifiers), forKey: "someName")

这是你从 UserDefaults 加载的地方

self.followedIdentifiers = Set(UserDefaults.standard.stringArray(forKey: "someName"))

【讨论】:

我可以用 Set 而不是 Array 做什么? 集合是保证对象的单个实例的集合。基本上,你不能添加重复的数组。当你在写博客时,我认为顺序很重要,也许NSMutableOrderedSet 会更好 它在同一个数组中不重复,在对象从 mainArray 转移到 followArray 后,mainArray 为空,因此它被重新填充,而 followArray 有那些被转移的对象,除了将要转移的新对象将来会添加。用户选择要传输的单元格。 @BroSimple 在哪里调用retrieveDataFromServer 我也看到了saveUserDefaults,但您还没有编辑数据库中的任何内容

以上是关于Swift:如何从我的表格视图中删除重复项?的主要内容,如果未能解决你的问题,请参考以下文章

Swift:在表格视图中过滤结果,因此它不会从 JSON 返回重复项

我无法在 Swift 中删除我的最后一个表格视图单元格

如何在 Swift 中同步表格视图和搜索栏选择?

iOS如何编辑(更新)日期我表格视图单元格解析Swift

如何在单元格 Swift 2 中删除项目后重新加载表格视图

如何更改 Swift 中表格视图单元格中的默认删除按钮?