2017-03-29 5 views
1

私は検索機能を実装するとバグがありました。私は非同期スレッドをオープンしました。しかし、文字(電話番号の数字)を削除すると、アプリがクラッシュします。***コレクション<__ NSArrayM:0x117d7320>が列挙されている間に突然変異しました。

エラー:

*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x117d7320> was mutated while being enumerated.'

はコード:

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{ 
    // 
    self.isSearch = YES; 

    //remove the last search all the contacts 
    [self.resultArr removeAllObjects]; 
    // 
    [self.rcs_SearchTableView reloadData]; 
    // 
    dispatch_queue_t uploadQueue = dispatch_get_global_queue(0, 0); 
    dispatch_queue_t getMainQueue = dispatch_get_main_queue(); 
    dispatch_async(uploadQueue, ^{ 

     NSMutableArray *phoneArr = (NSMutableArray *)[self rcs_GetPhoneNumberFromeDatabaseWithPhone:searchText]; 
     // 
     //NSLog(@"清空上次搜索的数据:%@", self.resultArr); 
     //NSLog(@"输入的关键字是---%@---%lu",searchText,(unsigned long)searchText.length); 
     if (0 == searchText.length || [searchText isEqualToString:@" "]) { 
      self.isSearch = NO; 
      //[self.rcs_SearchTableView reloadData]; 
      [self.resultArr removeAllObjects]; 
     } 
     //[self.rcs_SearchTableView reloadData]; 

     if (0 != phoneArr.count) { 
      // 
      for (NSUInteger i = 0; i < phoneArr.count; i ++) { 

       RCSPhoneModel *flagPhoneModel = phoneArr[i]; 


       for (NSUInteger i = 0; i < self.rcsRecentSearchDataSource.count; i ++) { 

        RCSContactModel *flagModel = self.rcsRecentSearchDataSource[i]; 

        if ([flagPhoneModel.serverId isEqualToString:flagModel.serverId] || [flagPhoneModel.phone isEqualToString:flagModel.name]) { 

         //the same contact has multiple Numbers To prevent repeated add the same contacts 
         if (![self.resultArr containsObject:flagModel]) { 

          [self.resultArr addObject:flagModel]; 
          continue; 
         } 
        } 
       } 
      } 

     }else{ 
      //search contacts by name 

      for (NSInteger i = 0; i < self.rcsRecentSearchDataSource.count; i ++) { 
       RCSContactModel *model = self.rcsRecentSearchDataSource[i]; 
       NSString *nameStr = model.name; 
       if (nameStr.length >= searchText.length) { 
        //search all the name 
        if ([nameStr containsString:searchText]) { 
         [self.resultArr addObject:model]; 
        } 
       } 
      } 
     } 
     // 
     if (self.resultArr.count > 0) { 
      self.isSearch = YES; 
      //[self.rcs_SearchTableView reloadData]; 
     } 
     //The phone contacts or local contact synchronized to the server 
     dispatch_async(getMainQueue, ^{ 

      [self.rcs_SearchTableView reloadData]; 
     }); 
    }); 
} 

答えて

1

forループは、他のスレッドに変更される可能性やそれがそのループ内で変更される可能性が何かを列挙してはいけません。列挙されている間に(別のスレッドまたはループ自体の中で)変更されないことが確実なオブジェクトのみを列挙する必要があります。これを行う1つの方法は、配列のローカルコピーを使用して列挙することだけです。

あなたforループで列挙されているものは、ループ内で変更された場合、私は見ることができないので、私はいくつかの他のスレッドでは、いくつかの他のコードでは、あなたがself.rcsRecentSearchDataSourcephoneArrのいずれかを変更していることを推測します。これにより、self.rcsRecentSearchDataSourceまたはphoneArrを列挙するforループがクラッシュし、列挙中に変更しないようにする必要があるためです。

これは本当に別のスレッドで実行する必要がありますか?

もしそうなら、配列のスレッドローカルコピーを使用して元の配列の代わりに列挙します。そうすれば、他のどのスコープにも存在しないので、他の誰もそれを変更できないことを確実にすることができます。

例えば、あなたがあなたのコードを変更することができます2つの場所があります

NSArray *localSearchDataSource = [self.rcsRecentSearchDataSource copy]; 

for (NSUInteger i = 0; i < localSearchDataSource.count; i ++) { 

とにあなたが変更される可能性が一つの場所:私はそれはとアンダーコードのように答えました

NSArray *localPhoneArr = [[self rcs_GetPhoneNumberFromeDatabaseWithPhone:searchText] copy]; 

for (NSUInteger i = 0; i < localPhoneArr .count; i ++) { 
+0

ありがとうございます。 "self.rcsRecentSearchDataSource" - この配列は変更されないデータソースで、コピーしないと思います。私にこの配列(self.resultArr)エラーを通知してください。 "self.resultArr"は検索結果です。私がキャラクターを入力したり、キャラクターを取り除くと、最初からすべてを取り除きます。 "self.result"とphoneArrは入力文字によって変わります。 –

+0

私はあなたの答えでそれをしますが、それは解決されません。全く同じことをありがとう。 –

+0

あなたの解決策によれば、私はすでに問題を解決しています。非常に感謝しています。 –

0

: (NSString *)searchText { // self.isSearch = YES; // if(0 == searchText.length || [searchText isEqualToString:@ ""]){ self.isSearch = NO; //[self.resultArr removeAllObjects]; } //すべての連絡先を最後に検索します。 [self.resultArr removeAllObjects]; // [self.rcs_SearchTableView reloadData]; // NSMutableArray * localSearchDataSource = [self.resultArr mutableCopy]; //元の配列と同様にオブジェクト配列を作成する //データの電話番号への入力アクセスに応じて NSArray * localPhoneArr = [[self rcs_GetPhoneNumberFromeDatabaseWithPhone:searchText] copy]; // //[self.rcs_SearchTableView reloadData]; if(0!= localPhoneArr.count){ //非同期スレッドを使用してデータ一致の数値が長くなると、 が送出されるので、dispatch_queue_t uploadQueue = dispatch_get_global_queue(0、0); dispatch_queue_t getMainQueue = dispatch_get_main_queue(); dispatch_async(uploadQueue、^ { // for(NSUInteger i = 0; i < localPhoneArr。カウント; i ++){ RCSPhoneModel * flagPhoneModel = localPhoneArr [i]; for(NSUInteger i = 0; i < self.rcsRecentSearchDataSource.count; i ++){ RCSContactModel * flagModel = self.rcsRecentSearchDataSource [i];

   if ([flagPhoneModel.serverId isEqualToString:flagModel.serverId] || [flagPhoneModel.phone isEqualToString:flagModel.name]) { 
        //The same contact has multiple Numbers To prevent repeated add the same contacts 
        if (![localSearchDataSource containsObject:flagModel]) { 

         [localSearchDataSource addObject:flagModel]; 
        } 
       } 
      } 
     } 
     //Add the search results to the search data source 
     dispatch_async(getMainQueue, ^{ 
      [self.resultArr addObjectsFromArray:localSearchDataSource]; 
      [self.rcs_SearchTableView reloadData]; 
     }); 
    }); 


}else{ 
    //Search contacts by name 

    for (NSInteger i = 0; i < self.rcsRecentSearchDataSource.count; i ++) { 
     RCSContactModel *model = self.rcsRecentSearchDataSource[i]; 
     NSString *nameStr = model.name; 
     if (nameStr.length >= searchText.length) { 
      //Search all name 
      if ([nameStr containsString:searchText]) { 
       [self.resultArr addObject:model]; 
      } 
     } 
    } 
} 
// 
if (self.resultArr.count > 0) { 
    self.isSearch = YES; 
    [self.rcs_SearchTableView reloadData]; 
} 

}

私は2つの変更を行った 'NSMutableArrayの* localSearchDataSource = [self.resultArr mutableCopy];'と 'NSArray * localPhoneArr = [[self rcs_GetPhoneNumberFromeDatabaseWithPhone:searchText] copy];'となります。そしてそれを終わらせる。コレクション< __NSArrayM:0x117d7320>が列挙されている間に突然変異しました。

関連する問題