SearchBar 如何通过 NSMutableArray 进行搜索?

Posted

技术标签:

【中文标题】SearchBar 如何通过 NSMutableArray 进行搜索?【英文标题】:How can a SearchBar search through a NSMutableArray? 【发布时间】:2017-12-11 19:35:47 【问题描述】:

我有一个NSMutableArray,我正在尝试创建一个搜索栏。我一直在寻找几个小时,但我找不到任何对我有帮助的东西,因为我将 NSMutableArray 与 Firebase 一起使用。我对斯威夫特有点陌生。我创建了一个表格视图和一个搜索栏。表格视图显示来自NSMutableArray 的数据。当用户在搜索栏上搜索时,我怎样才能做到这一点,然后整个帖子都会出现?

如果有一个帖子包含 2 个字符串和一个图像,一个字符串是“A City”,另一个字符串是帖子的标题,假设当用户只搜索帖子的标题时或者只有城市,然后显示整个帖子。如果结果可以在同一个viewcontroller 上,就像在同一个tableview 上一样。

到目前为止,我已经在我的viewDidLoad

func setUpSearchBar() 
    let searchController = UISearchController(searchResultsController: nil)
    navigationItem.searchController = searchController
    searchController.dimsBackgroundDuringPresentation = true
    definesPresentationContext = true
 

而我的数组是这样的:

var posts = NSMutableArray()

我真正写过的唯一内容是设置了搜索栏,但没有真正发挥作用,因为我没有找到任何可以帮助我的东西,而且我不知道如何进行搜索酒吧工作。到目前为止,我必须找到的所有教程都是非常普通的数组,例如:

var post = ["pear", "orange", "apple"]

但我找不到如何让搜索遍历我的帖子NSMutableArray

如果有人能帮助我解决这个问题,我会非常高兴。如果可能的话,我不想要直接的答案和一些解释,以便我可以学习并自己创建它。

这是下载数据并将其显示在TableView中的代码

import UIKit
import FirebaseStorage
import FirebaseDatabase
import FirebaseAuth
import FirebaseCore
import Firebase

class MainViewController: UIViewController, UITableViewDelegate, UITableViewDataSource 

@IBOutlet weak var postsTableView: UITableView!

var posts = NSMutableArray()

override func viewDidLoad() 
    super.viewDidLoad()

    setUpSearchBar()
    loadData()

    self.postsTableView.delegate = self
    self.postsTableView.dataSource = self

    // Uncomment the following line to preserve selection between presentations
    // self.clearsSelectionOnViewWillAppear = false

    // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
    // self.navigationItem.rightBarButtonItem = self.editButtonItem


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.



func loadData() 

    Database.database().reference().child("posts").queryOrdered(byChild: "timeorder").observeSingleEvent(of: .value)  (snapshot) in
        if let postsDictionary = snapshot.value as? [String: AnyObject] 
            for post in postsDictionary 
                self.posts.add(post.value)

            
            self.postsTableView.reloadData()
        
    





// MARK: - Table view data source

 func numberOfSections(in tableView: UITableView) -> Int 
    // #warning Incomplete implementation, return the number of sections
    return 1


 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    // #warning Incomplete implementation, return the number of rows
         return self.posts.count



 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PostTableViewCell
    // Configure the cell...
    let post = self.posts[indexPath.row] as! [String: AnyObject]
    cell.titleLabel.text = post["title"] as? String
    cell.contentTextView.text = post["content"] as? String
    cell.dateAndTimeLabel.text = post["time"] as? String
    cell.usernameLabel.text = post["username"] as? String
    cell.locationAdressLabel.text = post["adress"] as? String

        if let imageName = post["image"] as? String 

            let imageRef = Storage.storage().reference().child("images/\(imageName)")
            imageRef.getData(maxSize: 25 * 1024 * 1024)  (data, error) -> Void in
                if error == nil 
                    //successfull
                    let downloadedImage = UIImage(data: data!)

                    cell.postsImageView.image = downloadedImage
                else 
                    // error

                    print("there was an error downloading image: \(String(describing: error?.localizedDescription))")
            
        
    

            return cell
        


func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat 
    return 500.0


@IBAction func goToProfilePage(_ sender: Any) 
    let logoutSuccess = self.storyboard?.instantiateViewController(withIdentifier: "ProfileVC")
    self.present(logoutSuccess!, animated: true, completion: nil)



@IBAction func navigateButton(_ sender: Any) 
    let navigate = self.storyboard?.instantiateViewController(withIdentifier: "NavigateVC")
    self.present(navigate!, animated: true, completion: nil)


@IBAction func chooseCountry(_ sender: Any) 
    let navigate = self.storyboard?.instantiateViewController(withIdentifier: "CountryVC")
    self.present(navigate!, animated: true, completion: nil)




func setUpSearchBar() 

    let searchController = UISearchController(searchResultsController: nil)
    navigationItem.searchController = searchController
    searchController.dimsBackgroundDuringPresentation = true
    definesPresentationContext = true




这是将post 上传到 Firebase 的代码

import UIKit
import FirebaseDatabase
import FirebaseStorage
import FirebaseAuth
import Firebase

class PostViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPickerViewDataSource, UIPickerViewDelegate 

@IBOutlet weak var addImageButton: UIBarButtonItem!
@IBOutlet weak var pickCountryPicker: UIPickerView!
@IBOutlet weak var choosenCountryLabel: UILabel!
@IBOutlet weak var titleTextField: UITextField!

@IBOutlet weak var contentTextView: UITextView!

@IBOutlet weak var imageView: UIImageView!

@IBOutlet weak var locationAdressTextField: UITextField!


var imageFileName = ""

var timeStamps = ""
var secondTimeStamps = ""

override func viewDidLoad() 
    super.viewDidLoad()

    let currentDateTime = Date()

    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyy-MM-dd HH:mm"

    timeStamps = "\(dateFormatter.string(from: currentDateTime))"

    let secondDateFormatter = DateFormatter()
    secondDateFormatter.dateFormat = "yyyy-MM-dd HH:00:00"

    secondTimeStamps = "\(secondDateFormatter.string(from: currentDateTime))"

    // Do any additional setup after loading the view.


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


@IBAction func postButton(_ sender: Any) 

    if (self.imageFileName != "") 
        if choosenCountryLabel.text == "Afghanistan" 
        // image has finshed the uploading, Saving Post!!!
        if let uid = Auth.auth().currentUser?.uid 

            Database.database().reference().child("users").child(uid).observeSingleEvent(of: .value, with:  (snapshot) in
                if let userDictionary = snapshot.value as? [String: AnyObject] 
                    for user in userDictionary
                        if let username = user.value as? String 
                            if let streetAdress = self.locationAdressTextField.text 
                                if let title = self.titleTextField.text 
                                    if let content = self.contentTextView.text 
                                        let postObject: Dictionary<String, Any> = [
                                            "uid" : uid,
                                            "title" : title,
                                            "content" : content,
                                            "username" : username,
                                            "time" : self.timeStamps,
                                            "timeorder" : self.secondTimeStamps,
                                            "image" : self.imageFileName,
                                            "adress" : streetAdress
                                        ]

                                        Database.database().reference().child("posts").childByAutoId().setValue(postObject)
                                        Database.database().reference().child("Afghanistanposts").childByAutoId().setValue(postObject)
                                        Database.database().reference().child(uid).childByAutoId().setValue(postObject)

                                        let alertPosting = UIAlertController(title: "Successfull upload", message: "Your acty was successfully uploaded.", preferredStyle: .alert)
                                        alertPosting.addAction(UIAlertAction(title: "OK", style: .default, handler:  (action) in
                                            let vc = self.storyboard?.instantiateViewController(withIdentifier: "AfghanistanVC")
                                            self.present(vc!, animated: true, completion: nil)
                                        ))
                                        self.present(alertPosting, animated: true, completion: nil)



                                        print("Posted Succesfully to Firebase, Saving Post!!!")

                                        
                                    
                                
                            
                        
                    
                )
            

        
    else
        let alertNotPosting = UIAlertController(title: "Seems like you got connection problems", message: "Your image has not been uploaded. Please Wait 10 seconds and try again.", preferredStyle: .alert)
        alertNotPosting.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alertNotPosting, animated: true, completion: nil)
    
 @IBAction func addImage(_ sender: Any) 

    if addImageButton.isEnabled == false 
        let alertNotPosting = UIAlertController(title: "Image already Picked", message: "sorry you already have an image picked", preferredStyle: .alert)
        alertNotPosting.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
        self.present(alertNotPosting, animated: true, completion: nil)
    else 
        let picker = UIImagePickerController()
        picker.delegate = self
        self.present(picker, animated: true, completion: nil)
    


func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) 
    if let pickedImage = info[UIImagePickerControllerOriginalImage] as? UIImage 
        self.imageView.image = pickedImage
        uploadImage(image: pickedImage)
        picker.dismiss(animated: true, completion: nil)
        addImageButton.isEnabled = false

    


func imagePickerControllerDidCancel(_ picker: UIImagePickerController) 
    picker.dismiss(animated: true, completion: nil)


func uploadImage(image: UIImage)
    let randomName = randomStringWithLength(length: 10)
    let imageData = UIImageJPEGRepresentation(image, 1.0)
    let uploadRef = Storage.storage().reference().child("images/\(randomName).jpg")

    let uploadTask = uploadRef.putData(imageData!, metadata: nil)  metadata, error in
        if error == nil 
            //success
            print("SuccessFully uploaded")
            self.imageFileName = "\(randomName as String).jpg"
        else 
            // not success =  error

            print("error with the Image: \(String(describing: error?.localizedDescription))")

        
    


func randomStringWithLength(length: Int) -> NSString 
    let characters: NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
    var randomString: NSMutableString = NSMutableString(capacity: length)

    for i in 0..<length 
        var len = UInt32(characters.length)
        var rand = arc4random_uniform(len)
        randomString.appendFormat("%C", characters.character(at: Int(rand)))

    
    return randomString



func numberOfComponents(in pickerView: UIPickerView) -> Int 
    return 1


func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? 
    return countries[row]


func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int 
    return countries.count


func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) 
    choosenCountryLabel.text = countries[row]



下面是选择器的一个完整国家/地区的数组,不需要显示。

【问题讨论】:

不要使用NSMutableArray。它与 Swift 数组无关,您正在与强类型系统作斗争。只需使用var,您就可以免费获得可变性 @vadian 那么我应该使用什么 NSArray?还是? 不,使用 Swift 数组,[String][Post] 等。除非编译器告诉您需要它们,否则根本不要使用 NS... 集合类型(例如在一些 CoreFoundation函数调用和 Objective-C 桥接 inout 参数) 相信我,你绝对不需要NSMutableArray。再一次,var 关键字使任何 Swift 集合类型(ArrayDictionary)都是可变的。如果您需要引用类型,请使用类而不是结构 @Jiyar 如果您使用相关代码更新您的问题,显示您实际拥有什么以及您正在尝试做什么,这将非常有帮助。 【参考方案1】:

为什么不直接将 NSMutableArray 转换为 Swift 数组?为了安全起见,我建议使用 guard 声明,如下所示:

guard let swiftArrayPosts = posts as? [String] else return

然后你就可以使用像filter这样的Swift高阶函数来查找你想要的帖子了:

let filteredPosts = swiftArrayPosts.filter $0 == "MyQuery"

然后将filteredPosts 分配给您用来显示它们的任何数据源。

【讨论】:

我真的很难理解这个,我应该输入这个吗?在setUpSearchBar 函数中或上面,或者我会创建一个新函数,每当user 命中Search 时都会这样做? 需要查看更多代码才能理解您在说什么。没有原生的setUpSearchBar 函数。但是是的,您希望在用户输入查询时使用。 更新问题添加了我的上传代码和我的下载代码 首先。您需要将 searchController 的搜索栏分配给表视图标题视图 tableView.tableHeaderView = searchController.searchBar 在您的 setUpSearchBarFunction 中执行此操作 搜索栏已经在“导航”栏中,只要用户滚动到表格视图的顶部就会显示

以上是关于SearchBar 如何通过 NSMutableArray 进行搜索?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 SearchBar 和 for 循环返回对象数组

如何在带有部分的 TableView 上创建 SearchBar?

如何让 TableView 中的 SearchBar 看起来像设置应用程序中的那样

在导航栏中使 SearchBar 更高

当您尝试通过 alpha 隐藏 SearchBar 时,背景视图仍然可见

如何通过反应上下文保持价值?