- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
抱歉,我是 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/
我是 Xcode 的新手,所以请原谅我的无知。 我在 ViewController 上有一个 searchBar 和一个 tableView。我有一个用于 searchBar 的 IBOutlet 并
macOS 中函数 searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) 的类似方法是什么? 得到答案: @IB
我正在尝试构建一个充满多个可编辑 TextView 的 NSCollectionView。 (Swift 中的 OS X 应用程序。)我的 NSCollectionViewItem 子类称为 Note
我正在尝试为 tableView 实现搜索栏,但在我的 textDidChange 方法中收到错误“...二元运算符‘==’无法应用于‘Place’和‘String’类型的操作数”。 tableVie
我是 iOS 编程的新手,我不确定为什么我的 textDidChange 函数没有触发。在网上搜索了一堆,但找不到我的代码和其他人的代码有什么不同。这是我的 .h 和 .m 文件对于这个 View C
我正在做类似的事情: @IBOutlet var textView: NSTextView! override func viewDidLoad() { super.viewDidLoad()
抱歉,我是 swift 的初学者。 我有一个显示数据的 searchBar 和 tableView。 我还在 func“textDidChange”中调用 Api 到服务器。 但是,当我非常快速地输入
我有一个问题,我不知道为什么方法2取不到值? 方法一:可以取值! -(void) searchBar:(UISearchBar *) searchBar textDidChange:(NSString
我有一个 iPhone 应用程序,它包含一个 UITableView,顶部有一个 UISearchBar。当用户在 UISearchBar 中键入内容时,UITableView 的内容会被适本地过滤。
第一步.在xib中添加一个NSTextField 第 2 步。在 .h 文件中添加 NSTextFieldDelegate,按住 Control 键拖动 NSTextField 到文件的所有者以将委托
谁能解释一下为什么 textDidChange 没有处理我的委托(delegate),但 controlTextDidChange 从 NSTextField 工作。 - (void)control
我有一个自定义的 NSTextView 实现,可以自动调整字体大小,以便文本填充整个 View 。 我重写了 didChangeText 来调用我的字体大小调整方法。当用户编辑文本时效果很好,但是当通
我想搜索我的 plist 中的项目。 plist 由一组字典组成。每个键/值代表字符串/整数等,但这并不重要。 正如您将在下面的 tableViewController 类中看到的,我当前已经输入了一
我有一个 tableView,我正在其中从 Parse 加载我的数据。现在我想使用 parse 来显示来自 searchBar.text 的搜索结果。我有名字和姓氏,我都想在其中搜索。问题是我不知道如
我使用的是 iOS7,我有一个搜索栏。我正在使用 textDidChange 方法来获取每个字符并处理我的代码,当我们有文本时,我有明确的“X 按钮”。在以前的版本中,当点击清除按钮时,textDid
我已经创建了一个搜索栏并正在使用这个功能: func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
我目前面临与 UISearchBar 和听写支持相关的问题。当搜索栏的文本发生变化时,我必须触发一些过滤逻辑。必须通过键盘键入或听写来触发此逻辑。 现在这是我的问题:如果我在搜索栏中结束听写,text
我已经搜索了几个小时,但看不到解决方案...我正在使用输入到 UISearchBar 中的文本来过滤自定义对象数组,以更改下面表格 View 中的数据。经过一番调试后,我找到了问题的根源: func
我在以这种方式从 viewDidLoad 调用的函数中以编程方式创建了一个 UISearchBar //*************************************** //*** B
我正在 searchBar:textDidChange 中使用 Google 搜索内容: 我的问题是,每次按下一个字母时,它都会等待完成最后一个字母才能开始另一个字母。如果用户输入的速度非常快 - 你
我是一名优秀的程序员,十分优秀!