UITableViewController में UISearchDisplayController का उपयोग करते समय जोर विफलता


80

मैं अपने ऐप में TableViewController के लिए सरल खोज कार्यक्षमता जोड़ने की कोशिश कर रहा हूं। मैंने रे वेंडरलिच के ट्यूटोरियल का अनुसरण किया। मेरे पास कुछ डेटा के साथ एक तालिका दृश्य है, मैंने स्टोरीबोर्ड में खोज बार + प्रदर्शन नियंत्रक जोड़ा है, और फिर मेरे पास यह कोड है:

#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 में कोशिकाओं के लिए हैंडलिंग और डीक्यूइंग सिस्टम बदल गया है, और यह भी कि खोज एक अलग तालिका दृश्य का उपयोग करती है, इसलिए मुझे लगा कि समस्या यह थी कि फ़िल्टर किए गए परिणामों वाले खोज तालिका दृश्य सेल के बारे में नहीं जानते थे, इसलिए मैंने लगा दिया यह मेरे विचार में है

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

और वोइला! यह काम किया ... केवल पहली बार जब आप खोज करते हैं। यदि आप मूल परिणामों पर वापस जाते हैं और फिर से खोज करते हैं, तो ऐप उसी त्रुटि के साथ क्रैश हो जाता है। मैंने सोचा कि शायद सभी को जोड़ दिया जाए

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

सेलफ़ोररॉ विधि के लिए सामान, लेकिन यह dequeueReusableCellWithIdentifier: forIndexPath: विधि होने के पूरे उद्देश्य के खिलाफ नहीं जाता है? वैसे भी, मैं हार गया हूं। मैं क्या खो रहा हूँ? कृपया मदद करें। आपके सभी समय के लिए अग्रिम धन्यवाद (:

एलेक्स।

जवाबों:


194

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];

4
सिर्फ एक टेबल से दूसरी टेबल पर अनिश्चित काल तक नई कोशिकाओं को पलटना नहीं होगा? अगर एक टेबल से कोशिकाओं को ख़त्म किया जाए और उन्हें किसी बुरे विचार की तरह आवाज़ दी जाए
maltalef

1
मुझे लगा कि यह भी काम करेगा। यह नहीं है मेरे मामले में खोज तालिका के लिए मेरी मुख्य तालिका से सेल को हटाने की कोशिश करना कभी-कभी दुर्घटना का कारण बनता है।
ली प्रोबर्ट

1
काम नहीं करता है। खोज करने का प्रयास करें, फिर रद्द करें (ओवरले परिणाम मोड से बाहर निकलें) और फिर फिर से खोजें। दुर्घटना।
डैनियल

8
प्रस्तावित समाधान अभी भी मेरे लिए एक अपवाद को जन्म देता है। हालांकि, यह उम्मीद के रूप में अगर मैं की जगह काम करने लगता है dequeueReusableCellWithIdentifier:forIndexPath:द्वारा dequeueReusableCellWithIdentifier:
jweyrich

3
धन्यवाद! टेबलव्यू के बजाय self.tableview मुद्दा था! जीवन रक्षक!
अदामतले

14

यह कारण है कि यह पहले रन पर बहुत अच्छा काम करता है, लेकिन तब दुर्घटनाग्रस्त हो जाता है जब आप परिणाम तालिका से बाहर निकल जाते हैं और किसी अन्य खोज के लिए वापस चले जाते हैं, क्योंकि खोज प्रदर्शन नियंत्रक UITableViewआपके द्वारा खोज मोड में प्रवेश करने पर हर बार एक नया लोड कर रहा है।

खोज मोड से मेरा मतलब है, आपने टेक्स्टफ़ील्ड को टैप किया है और आप टाइप करना शुरू कर चुके हैं, जिस बिंदु पर परिणाम प्रदर्शित करने के लिए एक टेबल व्यू उत्पन्न होता है, इस मोड से बाहर निकलकर इसे रद्द बटन दबाकर हासिल किया। जब आप टेक्स्टफील्ड को दूसरी बार टैप करते हैं और फिर से लिखना शुरू करते हैं - यह दूसरी बार "खोज मोड" में प्रवेश कर रहा है।

तो दुर्घटना से बचने के लिए आपको अपने नियंत्रक विधि के बजाय searchDisplayController:didLoadSearchResultsTableView:प्रतिनिधि विधि (से UISearchDisplayDelegate) में तालिका दृश्य के लिए सेल वर्ग को पंजीकृत करना चाहिए viewDidLoad

निम्नलिखित नुसार:

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

इसने मुझे आश्चर्यचकित कर दिया क्योंकि iOS 7 पर ... तालिका दृश्य का पुन: उपयोग किया जा रहा है। इसलिए आप viewDidLoadचाहें तो क्लास रजिस्टर कर सकते हैं। विरासत की खातिर, मैं अपना पंजीकरण उस प्रतिनिधि विधि में रखूँगा जिसका मैंने उल्लेख किया था।


2
दुर्भाग्य से यह स्टोरीबोर्ड गतिशील प्रोटोटाइप कोशिकाओं के साथ काम नहीं करता है।
ऑर्टविन Gentz

लेकिन यह निब द्वारा पंजीकृत कोशिकाओं के साथ बहुत अच्छा काम करता है। अच्छा वर्कअराउंड।
थॉमस वर्बेक

12

खोज करने के बाद, CellForRowAtIndexPath विधि का 'tableView' लगता है कि आपके द्वारा परिभाषित तालिका का कोई उदाहरण नहीं है। तो, आप उस तालिका के एक उदाहरण का उपयोग कर सकते हैं जो सेल को परिभाषित करता है। के बजाय:

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

उपयोग:

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

( CellForRowAtIndexPath पद्धति के तालिका दृश्य का उपयोग न करें, self.tableView का उपयोग करें )


2
+1। इस अवधारणा के मेरे तेजी से कार्यान्वयन में self.tableView की आवश्यकता है।
डेविडेथेल

3

'इंडेक्सपाथ' का उपयोग किए बिना सेल को हटा दें और यदि आप शून्य तत्व प्राप्त करते हैं, तो आपको इसे मैन्युअल रूप से आवंटित करना होगा।

- (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 का उपयोग करने की कोशिश करने से क्रैश हो सकता है। इसके बजाय यह कोड किसी भी स्थिति में काम करता है।


1
यह अभ्यस्त काम करता है यदि आपका सेल स्टोरीबोर्ड में कस्टम है और इसे तत्काल से हटाने की आवश्यकता है, न कि इसके वर्ग की।
ली प्रॉबर्ट

3

जब मुझे यह समस्या थी, तो समाधान tableViewdequeueReusableCellWithIdentifier की जगह ले रहा था : @ साथself.tableView


2

मैं उस ट्यूटोरियल पर भी काम कर रहा हूं। डिफ़ॉल्ट TableViewController में "forIndexPath" है और उनके उदाहरण में यह मौजूद नहीं है। एक बार मैंने इसे खोज कार्य से हटा दिया।

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

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

1
दुर्भाग्य से यह स्टोरीबोर्ड गतिशील प्रोटोटाइप कोशिकाओं के साथ काम नहीं करता है।
ऑर्टविन गेंट्ज़

2

स्विफ्ट 3 के लिए आपको बस स्व जोड़ने की आवश्यकता है:

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

    ...
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.