gpt4 book ai didi

ios - 为什么 searchBar "textDidChange"获取服务器请求并出错并崩溃

转载 作者:行者123 更新时间:2023-11-30 12:00:10 24 4
gpt4 key购买 nike

抱歉,我是 swift 的初学者。
我有一个显示数据的 searchBar 和 tableView。
我还在 func“textDidChange”中调用 Api 到服务器。
但是,当我非常快速地输入或删除文本时,我的应用程序崩溃了,并且收到如下行所示的错误消息。
如何防止这种情况发生?
谢谢。

fatal error: Index out of range

override func viewDidLoad() {

self.subscribe = contacts.notifySubject.subscribe({ json in
self.tableView.reloadData()
})
}

func doSearch() {
if let word = searchBar.text {
if word.isEmpty == false {
contacts.searchFriend(word)
}
} else {
tableView.reloadData()
}
}

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

if searchText.isEmpty == true {

contacts.friends.removeAll(keepingCapacity: false)
tableView.reloadData()
return
}else{

doSearch()
}
}

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

if contacts.friends.isEmpty == false {
return contacts.friends.count
}
return 0
}

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


if contacts.friends.isEmpty == false {

guard contacts.friends.count != 0 else { return UITableViewCell() } // don't prevent crash

let cell: SearchTableViewCell = SearchTableViewCell(style: .default, reuseIdentifier: "SearchTableViewCell")
let user:User = contacts.friends[indexPath.row]
cell.labelName.text = user.name
return cell
}

let cell = UITableViewCell()

return cell
}


class Contacts:Model {

var friends:[User] = [User]()

func searchFriend(_ word:String) {
if word.isEmpty {
return
}
self.friends.removeAll(keepingCapacity: false)
var params:[String:Any] = [String:Any]()
params["value"] = keyword
api.searchUser.get( params, { json in

json.forEach({ (index,data) in

let user = User(data)
if user.isExist {
self.friends.append(user)
}
})
self.notifySubject.onNext(json)
})
}

}

最佳答案

如果您在服务器上搜索文本更改,则意味着您正在连续调用 API。在第一个请求完成之前,您将发出下一个请求。因此,当您收到第一个请求的响应并重新加载 TableView 时,另一个请求再次完成,调用了 TableView 的重新加载。在这里,当 TableView 重新加载正在进行时,您从数组中删除对象,因此您的应用程序崩溃了。您应该在进行新的 API 调用之前取消之前的 API 调用。使用 NSOperation 和 NSOperationQueue 来实现此功能。

编辑

这是我用来从服务器搜索公交车站的示例使用 AFNetworking 的 API 调用

 func getStops(sessionManager:AFHTTPSessionManager, parameters:[AnyHashable:Any],completionHandler:@escaping (_ status:Bool, _ responseObject:Any)->()){

if !ReachabilityManager.shared.isReachable {
let error = WSError()
error.errorTitle = "Network error"
error.errorDescription = "Unable to connect, please check your internet connectivity."
completionHandler(false,error)
return
}

self.showNetworkActivity()

if let deviceId = SSKeychain.uniqueDeviceId(){
sessionManager.requestSerializer.setValue(deviceId, forHTTPHeaderField: X_DEVICE_ID)
}

if let accessToken = DBManager.logged?.accessToken{
sessionManager.requestSerializer.setValue(accessToken, forHTTPHeaderField: X_ACCESS_TOKEN)
}

if let simulatedContextId = self.simulatedContextId {
sessionManager.requestSerializer.setValue(simulatedContextId, forHTTPHeaderField: X_SIMULATE_CONTEXT)
}
if let languageCode = NSLocale.current.languageCode{
sessionManager.requestSerializer.setValue(languageCode, forHTTPHeaderField: X_LOCALE_ID)
}
let urlPath = WSApi.apiVersion + "stops"

sessionManager.get(urlPath, parameters: parameters, progress: { progress in

}, success: {[unowned self] task, responseObject in
self.hideNetworkActivity()
self.getCurretnContext(task: task)

var stops = [Stop]()

if let array = responseObject as? [[AnyHashable:Any]]{
stops.append(contentsOf: Stop.GetSports(array: array))
}

completionHandler(true,stops)

}, failure: {[unowned self] operation, err in
self.hideNetworkActivity()
self.getCurretnContext(task: operation)
let error = WSError(error: err as NSError)
error.getStatusCode(operation: operation)
if error.isUnauthorised{
AppDelegate.shared.handleUnAuthorised(error: error)
return
}
completionHandler(false,error)

})
}

ViewController 实现

 protocol StopSearchViewControllerDelegate : NSObjectProtocol {

/**
* Called when a place has been selected from the available autocomplete predictions.
* @param viewController The |StopSearchViewController| that generated the event.
* @param stop The |Stop| that was returned.
*/
func viewController(_ viewController: StopSearchViewController, didAutocompleteWith stop: Stop)

/**
* Called when a non-retryable error occurred when retrieving autocomplete predictions or place
* details. A non-retryable error is defined as one that is unlikely to be fixed by immediately
* retrying the operation.
* All other error codes are non-retryable.
* @param viewController The |StopSearchViewController| that generated the event.
* @param error The |WSError| that was returned.
*/
func viewController(_ viewController: StopSearchViewController, didFailAutocompleteWithWSError error: WSError)


/**
* Called when the user taps the Cancel button in a |StopSearchViewController|.
* @param viewController The |StopSearchViewController| that generated the event.
*/
func autocompleteWasCancelled(_ viewController: StopSearchViewController)
}

class StopSearchViewController: UIViewController {

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

weak var delegate:StopSearchViewControllerDelegate?

fileprivate var stops = [Stop]()

fileprivate var isNavigationBarHidden = false

override func viewDidLoad() {
super.viewDidLoad()

// Do any additional setup after loading the view.
self.tableView.tableHeaderView = UIView()
self.searchBar.becomeFirstResponder()

}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
self.isNavigationBarHidden = self.navigationController?.isNavigationBarHidden ?? false
self.navigationController?.isNavigationBarHidden = true
}

override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.navigationController?.isNavigationBarHidden = isNavigationBarHidden
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

fileprivate func loadStops(parameters:[AnyHashable:Any]){
WSApi.sharedManager.operationQueue.cancelAllOperations()
WSApi.shared.getStops(sessionManager: WSApi.sharedManager, parameters: parameters) {[weak self] (status, responseObject) in
if let strongSelf = self {
strongSelf.stops.removeAll()
if let stops = responseObject as? [Stop]{
if !strongSelf.searchBar.text!.isEmpty{
strongSelf.stops.append(contentsOf: stops)
}
}
strongSelf.tableView.reloadData()
}
}
}

fileprivate func closeViewController(){
if let navigationController = self.navigationController{
navigationController.popViewController(animated: true)
}else{
self.dismiss(animated: true, completion: nil)
}
}

override var preferredStatusBarStyle: UIStatusBarStyle{
return .lightContent
}

override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation{
return .none
}

override var prefersStatusBarHidden: Bool{
return false
}

}

extension StopSearchViewController :UITableViewDataSource{

func numberOfSections(in tableView: UITableView) -> Int {
return 1
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stops.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: StopSearchCell.reuseIdentifier, for: indexPath) as! StopSearchCell
let stop = stops[indexPath.row]
cell.configureCell(stop: stop)
return cell
}

func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 0
}

func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 20
}

func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let attrs = [NSFontAttributeName : UIFont(name: "Helvetica", size: 14)!, NSForegroundColorAttributeName:UIColor.lightGray]
let attributedString = NSMutableAttributedString(string:"powered by ", attributes:attrs)
let bAttrs = [NSFontAttributeName : UIFont(name: "Helvetica", size: 15)!, NSForegroundColorAttributeName:UIColor.darkGray]
let boldString = NSMutableAttributedString(string:"Change Transit", attributes:bAttrs)
attributedString.append(boldString)
let frame = CGRect(x: 0, y: 0, width: tableView.frame.width, height: 44)
let label = UILabel(frame: frame)
label.textAlignment = .center
label.attributedText = attributedString
return label
}


}

extension StopSearchViewController :UITableViewDelegate{

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let stop = stops[indexPath.row]
self.delegate?.viewController(self, didAutocompleteWith: stop)
// self.closeViewController()
}

}

extension StopSearchViewController :UISearchBarDelegate{


func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// guard !searchText.isEmpty else {
// WSApi.sharedManager.operationQueue.cancelAllOperations()
// self.stops.removeAll()
// self.tableView.reloadData()
// return
// }
let parameters = ["data_set_id":WSApi.shared.currentContextId ?? "","search_text": searchText]
self.loadStops(parameters: parameters)
}

func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {
self.delegate?.autocompleteWasCancelled(self)
// self.closeViewController()
}

}

关于ios - 为什么 searchBar "textDidChange"获取服务器请求并出错并崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47345518/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com