web-dev-qa-db-ja.com

UITableViewControllerでUISearchDisplayControllerを使用する場合のアサーションエラー

私は単純な検索機能をアプリのTableViewControllerに追加しようとしています。 Ray Wenderlichのチュートリアルに従いました。いくつかのデータを含むtableViewがあり、ストーリーボードに検索バー+ディスプレイコントローラーを追加し、次のコードを取得しました

#pragma mark - Table View
     - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"BreedCell" forIndexPath:indexPath];

        //Create PetBreed Object and return corresponding breed from corresponding array
        PetBreed *petBreed = nil;

        if(tableView == self.searchDisplayController.searchResultsTableView)
            petBreed = [_filteredBreedsArray objectAtIndex:indexPath.row];
        else
            petBreed = [_breedsArray objectAtIndex:indexPath.row];

        cell.accessoryType  = UITableViewCellAccessoryDisclosureIndicator;
        cell.textLabel.text = petBreed.name;

        return cell;
    }

#pragma mark - Search
    -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString {
        [_filteredBreedsArray removeAllObjects];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",searchString];
        _filteredBreedsArray = [[_breedsArray filteredArrayUsingPredicate:predicate] mutableCopy];

        return YES;
    }

    -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption {
        // Tells the table data source to reload when scope bar selection changes

        [_filteredBreedsArray removeAllObjects];
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.name contains[c] %@",self.searchDisplayController.searchBar.text];
        _filteredBreedsArray = [[_breedsArray filteredArrayUsingPredicate:predicate] mutableCopy];
        return YES;
    }

標準的なものですが、検索バーにテキストを入力すると、このエラーで毎回クラッシュします:

2013-01-07 19:47:07.330 FindFeedo[3206:c07] *** Assertion failure in -[UISearchResultsTableView dequeueReusableCellWithIdentifier:forIndexPath:], /SourceCache/UIKit_Sim/UIKit-2372/UITableView.m:4460
2013-01-07 19:47:07.330 FindFeedo[3206:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unable to dequeue a cell with identifier BreedCell - must register a nib or a class for the identifier or connect a prototype cell in a storyboard'

IOS 6では、セルの処理およびデキューシステムが変更されたこと、また検索で別のtableViewが使用されることを理解しているため、フィルタリングされた結果の検索tableViewがセルを認識していないことが問題だと思ったので、これは私のviewDidLoadで:

[self.searchDisplayController.searchResultsTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"BreedCell"];

そして出来上がり!うまくいった...初めて検索したときだけ。元の結果に戻って再度検索すると、同じエラーでアプリがクラッシュします。多分すべてを追加することを考えました

if(!cell){//init cell here};

cellForRowメソッドに追加しますが、dequeueReusableCellWithIdentifier:forIndexPath:メソッドを持つという目的全体に反することはありませんか?とにかく、私は失われました。私は何が欠けていますか?助けてください。いつもよろしくお願いします(:

アレックス。

79
acib708

DequeueReusableCellWithIdentifierでtableViewの代わりにself.tableViewを使用してみてください。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"BreedCell"];

    //Create PetBreed Object and return corresponding breed from corresponding array
    PetBreed *petBreed = nil;

    if(tableView == self.searchDisplayController.searchResultsTableView)
        petBreed = [_filteredBreedsArray objectAtIndex:indexPath.row];
    else
        petBreed = [_breedsArray objectAtIndex:indexPath.row];

    cell.accessoryType  = UITableViewCellAccessoryDisclosureIndicator;
    cell.textLabel.text = petBreed.name;

    return cell;
}

このコードはかなりうまく機能します

カスタムの高さセルがある場合は、使用しないでください

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

代わりにこれを使用してください

[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
193
FunkyKat

最初の実行でうまく機能したが、結果テーブルを終了して別の検索に戻った場合にクラッシュする理由は、検索表示コントローラーが検索モードに入るたびに新しいUITableViewをロードしているためです。

つまり、検索モードでは、テキストフィールドをタップし、入力を開始しました。この時点で、結果を表示するためにテーブルビューが生成され、キャンセルボタンを押すことでこのモードを終了します。テキストフィールドを2回タップして、もう一度入力を開始すると、これが2回目の「検索モード」になります。

したがって、クラッシュを回避するために、テーブルビューのセルクラスを登録して、コントローラーのUISearchDisplayDelegateメソッドではなく、searchDisplayController:didLoadSearchResultsTableView:デリゲートメソッド(viewDidLoadから)で使用する必要があります。 。

次のように:

- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
    [tableView registerClass:[DPContentTableCell class] forCellReuseIdentifier:cellIdentifier];
    [tableView registerClass:[DPEmptyContentTableCell class] forCellReuseIdentifier:emptyCellIdentifier];
}

IOS 7では...テーブルビューが再利用されているため、これは驚きでした。必要に応じて、viewDidLoadにクラスを登録できます。レガシーのために、私が言及したデリゲートメソッドに登録を保持します。

14
Daniel

検索後、cellForRowAtIndexPathメソッドの「tableView」は、定義したテーブルのインスタンスではないようです。そのため、セルを定義するテーブルのインスタンスを使用できます。の代わりに:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

つかいます:

UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

(cellForRowAtIndexPathメソッドのtableViewを使用しないでください。self.tableViewを使用してください。)

12
aqubi

「indexPath」を使用せずにセルをデキューします。nil要素を取得した場合は、手動で割り当てる必要があります。

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCellId"];
    if (!cell)
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YourCellId"];

    // fill your cell object with useful stuff :)

    return cell;
}

セルのデキューにself.tableViewを使用しようとすると、セクション化されたメインリストと単純な検索リストがある場合にクラッシュが発生する可能性があります。代わりに、このコードはどのような状況でも機能します。

3

この問題が発生したとき、解決策はtableView dequeueReusableCellWithIdentifier:@yourcellをself.tableView

3
glorio

for Swift 3 selfを追加するだけです:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
    let cell = self.tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! YourCell

    ...
}
2
Eugene Gordin

私もそのチュートリアルに取り組んでいます。デフォルトのTableViewControllerには「forIndexPath」があり、彼の例では存在しません。削除すると、検索が機能します。

//Default code
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];

//Replace with
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
2
sonicbabbler