Swift搜索栏和CoreData

huangapple go评论59阅读模式
英文:

Swift Search Bar and Coredata

问题

I added the data from Core Data to the table view. I also wanted to add a search bar. Whatever I did, only one NSManagedObject is added according to the words written in the search bar. How can I show objects containing the same words?

When the user finishes the search, there is only one object left!

class ViewController: UIViewController {

    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!

    var data = [NSManagedObject]()

    var selectedData: NSManagedObject?

    override func viewDidLoad() {
        super.viewDidLoad()

        searchBar.delegate = self
        tableView.dataSource = self
        tableView.delegate = self
        getData()
    }
}

extension ViewController: UISearchBarDelegate {

    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String){

        // Capitalized ilk harfi büyük diğer harfleri küçük yapıyor
        for word in data {

            if let wordy = word.value(forKey: "title") as? String {
                if wordy.capitalized.contains(searchText.capitalized) {
                    data.removeAll(keepingCapacity: false)
                    data.append(word)
                    tableView.reloadData()
                }
            }
        }
    }
}
英文:

I added the data from Coredata to the tableview. I also wanted to add a search bar. Whatever I did, only one NSManagedObject is added according to the words written in the search bar. How can I show objects containing the same words?

When the user finishes the search, there is only one object left!

class ViewController: UIViewController {

    @IBOutlet weak var searchBar: UISearchBar!
    @IBOutlet weak var tableView: UITableView!
    
   

    var data = [NSManagedObject]()
    
    var selectedData : NSManagedObject?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        
        searchBar.delegate = self
        tableView.dataSource = self
        tableView.delegate = self
        getData()
    }
}

extension ViewController: UISearchBarDelegate {
        
    func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String){
                
        // Capitalized ilk harfi büyük diğer harfleri küçük yapıyor
        for word in data {
            
            if let wordy = word.value(forKey: "title") as? String {
                if wordy.capitalized.contains(searchText.capitalized) {
                    data.removeAll(keepingCapacity: false)
                    data.append(word)
                    tableView.reloadData()
                }
            }
        }
    }
}

答案1

得分: 0

问题在于一旦找到包含 searchText 的第一个单词,您就调用 data.removeAll(keepingCapacity: false)。这意味着您清除了整个数组。然后重新插入您当前正在检查的单词。

然后,for 循环立即停止,因为现在数据数组中只有一个项目,而这个项目刚刚被处理。循环结束,您只剩下一个项目。

我建议您采取以下步骤:
维护第二个单词数组,只包括您想显示的单词。

var filteredWords = [NSManagedObject]()
...

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    filteredWords = []
    for word in data {
        if let wordy = word.value(forKey: "title") as? String {
            if wordy.capitalized.contains(searchText.capitalized) {
                filteredWords.append(word)
            }
        }
    }
    tableView.reloadData()
}

首先,创建一个新变量来保存过滤后的单词。这样,您始终保持 data 数组不受修改,因此您永远不会失去这些单词。
然后,在 searchBar(.. textDidChange:) 中,您首先清空 filteredWords,然后再添加新项。以确保您不会显示不想显示的条目。
您循环遍历数据条目,并每次找到匹配的单词时,将其放入 filteredWords 列表中。
另外:tableView.reloadData() 应该仅在 for 循环完成后调用。

然后,您需要调整 UITableViewDelegate 方法中的代码,以使用 filteredData 而不是 data

还有进一步改进的方法,如使用 filteredWords = data.filter { ... },或者简单地在输入更改时每次进行新的 CoreData 获取请求。但使用上述方法将解决您的问题。

英文:

The issue is that once you find the first word that contains the searchText, you call data.removeAll(keepingCapacity: false). That means you clear the entire array. Then you re-insert the one word that you are currently checking.

Then the for loop immediately stops, because well, there's only one item in the data array now and this one was just handled. The loop is done and you are left with only one item.

What I suggest you do is the following:
Hold a second array of words, but just the ones that you want to show.

var filteredWords = [NSManagedObject]()
...
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
    filteredWords = []
    for word in data {
        if let wordy = word.value(forKey: "title") as? String {
            if wordy.capitalized.contains(searchText.capitalized) {
                filteredWords.append(word)
            }
        }
    }
    tableView.reloadData()
}

So first you create a new variable to hold the filtertedWords. So you keep the data array always unmodified, so you never lose the words.
Then inside the searchBar(.. textDidChange:) you first clear the filteredWords before adding new items in. To make sure you don't keep entries shown you don't want to show.
You loop over your data entries and each time you find a word that matches, you put it into your filteredWords list.
Also: tableView.reloadData() should only be called when the for loop has finished.

Afterwards you will need to adjust your code in the UITableViewDelegate methods to use filteredData instead of data.

There are further ways to make this nicer like using filteredWords = data.filter { ... } or by simply making new CoreData fetch requests every time the input changes. But using the approach above will fix your issues.

huangapple
  • 本文由 发表于 2023年3月8日 15:55:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75670515.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定