Панель поиска с объектами JSON в TableView - Swift - PullRequest
0 голосов
/ 14 ноября 2018
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,UISearchBarDelegate,UISearchDisplayDelegate{

@IBOutlet weak var recipeTable: UITableView!

@IBOutlet weak var searchbarValue: UISearchBar! 

// search functionality

var filteredAnswers: [JSON]?


func searchBarSearchButtonClicked(_ searchBar: UISearchBar){

    self.filteredAnswers?.removeAll()
    if (searchBar.text?.isEmpty)! {
        self.filteredAnswers = self.recipes     } else {
        if self.recipes.count > 0 {
            for i in 0...self.recipes.count - 1 {
                let answer = self.recipes[i] as [Dictionary<String, AnyObject>]
                if answer.title.range(of: searchBar.text!, options: .caseInsensitive) != nil {
                    self.filteredAnswers.append(answer)
                }
            }
        }
    }
    recipeTable.reloadData();
    recipeTable.reloadInputViews();
    searchBar.resignFirstResponder()
}





//end search parameters


// tableview functionionalitys
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

    return recipes.count

}


// tableview functionalities
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! RecipeTableViewCell

    cell.recipeLabel.text = recipes[indexPath.row].title
    //cell.textLabel?.text = recipe.title
    //cell.imageView?.image = recipe.imageUrl

    return cell

}


// structs for json
struct Root : Decodable {
    let count : Int
    let recipes : [Recipe]
}

struct Recipe : Decodable { // It's highly recommended to declare Recipe in singular form
    let recipeId : String
    let imageUrl, sourceUrl, f2fUrl : URL
    let title : String
    let publisher : String
    let socialRank : Double
    let page : Int?
    let ingredients : [String]?
}

//recipes is array of Recipes
var recipes = [Recipe]() // array of recipes

//unfiltered recipes to put into search
var filteredRecipes = [Recipe]()




fileprivate func getRecipes() {

    let jsonURL = "http://food2fork.com/api/search?key=264045e3ff7b84ee346eb20e1642d9d9"
        //.data(using: .utf8)!

    //let somedata = Data(jsonURL.utf8)

    guard let url = URL(string: jsonURL) else{return}

    URLSession.shared.dataTask(with: url) {(data, response , err) in
        if let response = response as? HTTPURLResponse, response.statusCode != 200 {
            print(response.statusCode)
            return
        }
        DispatchQueue.main.async {

            if let err = err{
                print("failed to get data from URL",err)
                return
            }
            guard let data = data  else{return}
            //print(String(data: data, encoding: .utf8))
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let result = try decoder.decode(Root.self, from: data)
                self.recipes = result.recipes
                //print(result.recipes)
                self.recipeTable.reloadData()
            }catch let jsonERR {
                print("Failed to decode",jsonERR)
            }
        }

    }.resume()

}



override func viewDidLoad() {

    super.viewDidLoad()

    //search functionalities

     self.searchbarValue.delegate = self

    //call json object
    getRecipes()
  } 
}

Я пытаюсь реализовать панель поиска, которая берет ингредиенты из объекта JSON и показывает рецепты, содержащие эти ингредиенты, в моем табличном представлении. Я надеюсь на несколько лучших практик и помогу с этим. Я испробовал несколько разных стратегий, но ни одна из них не работает

Это последнее, что я пытался реализовать, но я получаю ошибки в функции поиска.

self.recipes.count в searchBarSearchButtonClicked Невозможно присвоить значение типа '[ViewController.Recipe]' для ввода '[JSON]?

Но я также получаю ошибку подтверждения в -

[UISearchResultsTableView _dequeueReusableCellWithIdentifier: forIndexPath: usingPresentationValues:]

Я хотел бы получить помощь, но также улучшить и найти лучший способ сделать это. Благодарю.

1 Ответ

0 голосов
/ 14 ноября 2018

Прежде всего ваша логика фильтрации рецептов не может работать и очень, очень неэффективна. Кажется, вы скопировали и вставили код из совершенно не связанного источника.

В основном, тип массива источника данных и тип фильтруемого массива должны быть одинаковыми, поэтому вы должны использовать filteredRecipes вместо filteredAnswers.

Для фильтрации рецептов по соответствующим ингредиентам используйте filter и contains

func searchBarSearchButtonClicked(_ searchBar: UISearchBar){

    filteredRecipes.removeAll()
    if let searchText = searchBar.text, !searchText.isEmpty {
        self.filteredRecipes = self.recipes.filter { recipe in 
            guard let ingredients = recipe.ingredients else { return false }
            return ingredients.contains { $0.range(of: searchText, options: .caseInsensitive) != nil }
        }
    } else {
        self.filteredRecipes = self.recipes 
    } 

    recipeTable.reloadData();
    recipeTable.reloadInputViews();
    searchBar.resignFirstResponder()
}

На самом деле этот код должен выполняться в методе делегата

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

, а не searchBarSearchButtonClicked

И - очень важно - вам нужно добавить логическое свойство для указания isSearching, а во всех связанных методах источника данных и делегата вы должны добавить условие для отображения данных filteredRecipes, если isSearching - true.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...