为什么UISearchBar调用textDidChange时我的iOS App会崩溃?
崩溃原因及修复方案
核心崩溃原因1:filteredArray被多次转为不可变数组
你代码中两次对filteredArray赋值为不可变类型,后续调用可变数组方法(removeAllObjects/addObject)时触发方法不识别崩溃:
viewDidLoad中,你先初始化filteredArray为可变数组,随后执行filteredArray = [songTitlesArray copy];,copy返回的是不可变NSArray类型helper方法中搜索框为空时,又执行filteredArray = [songTitlesArray copy];,再次把可变数组替换为不可变数组
核心崩溃原因2:后台线程执行UI操作
你通过performSelectorInBackground把helper放到后台线程执行,方法末尾调用[self.tableView reloadData]属于UI操作,苹果要求所有UI操作必须在主线程执行,后台线程执行UI会大概率触发崩溃或显示异常
核心崩溃原因3:多线程操作数组无安全保护
连续快速输入时多个后台线程同时修改filteredArray,会导致数据错乱甚至崩溃
修复代码
1. 修正viewDidLoad中filteredArray初始化
// 原错误代码 // filteredArray = [[NSMutableArray alloc] init]; // filteredArray = [songTitlesArray copy]; // 替换为 filteredArray = [songTitlesArray mutableCopy];
2. 修正searchBar:textDidChange:方法,避免不必要的后台线程
如果你的歌曲数量没有超过几千条,直接在主线程处理过滤完全足够,不需要开后台线程:
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ NSLog(@"search changed"); [self helper]; }
3. 修正helper方法逻辑,避免数组类型错误,主线程刷新UI
-(void)helper{ [filteredArray removeAllObjects]; NSString *searchText = self.searchBar.text; if (searchText.length == 0){ // 不要直接copy赋值,用addObjectsFromArray保持filteredArray可变类型 [filteredArray addObjectsFromArray:songTitlesArray]; } else { for (NSString *object in songTitlesArray){ // 增加不区分大小写搜索,更符合用户习惯 NSRange matchRange = [object rangeOfString:searchText options:NSCaseInsensitiveSearch]; if (matchRange.location != NSNotFound){ [filteredArray addObject:object]; } } } // 强制在主线程刷新表格 dispatch_async(dispatch_get_main_queue(), ^{ [self.tableView reloadData]; }); }
额外优化建议
你当前定义的songsQuery、songsArray、filteredArray、songTitlesArray都是全局变量,建议改为类的私有属性,避免多个实例之间数据互相干扰。
内容的提问来源于stack exchange,提问作者useruser
相关产品推荐
相关产品推荐

