0

我的要求: 我在索引標題是英文字母的首字母(另外一個搜索圖標索引表視圖上市的人按字母順序排列的名字的這個簡單的要求在頂部和#顯示以數字和其他特殊字符開頭的misc值)。iPhone通訊錄應用程序樣式的索引表視圖實現

我迄今所做的: 1.我使用的核心數據進行存儲和「姓氏」被模擬爲在聯繫人實體的字符串屬性 2.我使用NSFetchedResultsController來顯示索引排序表視圖。

完成我的要求的問題: 1.首先,我無法得到部分索引標題爲字母的第一個字母。戴夫在下面的帖子中的建議,幫助我達到了同樣的效果:NSFetchedResultsController with sections created by first letter of a string

我遇到的唯一問題是戴夫的建議是我無法獲得名爲「#」索引下的misc命名組合。

我曾嘗試: 1.我嘗試添加自定義的比較方法的NSString(類別),檢查如何比較和部分製作,但如果在NSSortDescriptor選擇指定自定義方法不會被調用。

下面是一些代碼:

@interface NSString (SortString) 

-(NSComparisonResult) customCompare: (NSString*) aStirng; 

@end 

@implementation NSString (SortString) 

-(NSComparisonResult) customCompare:(NSString *)aString 
{ 
NSLog(@"Custom compare called to compare : %@ and %@",self,aString); 
return [self caseInsensitiveCompare:aString]; 
} 

@end

代碼來獲取數據:

NSArray *sortDescriptors = [NSArray arrayWithObject:[[[NSSortDescriptor alloc] initWithKey:@"last_name" 
       ascending:YES selector:@selector(customCompare:)] autorelease]]; 

    [fetchRequest setSortDescriptors:sortDescriptors]; 
     fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest 
      managedObjectContext:managedObjectContext sectionNameKeyPath:@"lastNameInitial" cacheName:@"MyCache"]; 

你能不能讓我知道我缺少,以及如何要求能實現呢?

回答

4

這是一個非常低效的第一遍解決這個問題,我將最終重寫。但希望這會幫助你。

這是爲了「保證」在點擊「標準」部分索引視圖時獲取真正的表格部分索引。標準部分索引視圖應該有一個用於搜索的放大鏡圖標,一個用於非字母部分的散列標記(#),以及用於字母部分的字母A至Z。

無論有多少個真實部分或它們是由什麼組成,都會呈現此標準視圖。

此代碼最終將部分視圖索引映射到獲取的結果控制器中的真實存在的字母部分名稱路徑,或映射到實際存在的非字母(數字)部分或表頭中的搜索字段。

用戶只會偶爾在節索引的每次觸摸上重新創建節索引映射數組(_idxArray),但在每次觸摸時重新創建數組顯然效率低下,並且可以調整以緩存預先計算的結果。例如,我可以將sectionIndexTitleLetters的靜態字符串從頭開始全部大寫。不過,在3GS手機上速度足夠快,所以最近我還沒有重新訪問。

在標題:

static NSString *sectionIndexTitleLetters = @"abcdefghijklmnopqrstuvwxyz"; 

在表視圖數據源的實現:

- (NSArray *) sectionIndexTitlesForTableView:(UITableView *)tv { 
    if (tv != searchDisplayController.searchResultsTableView) { 
     NSMutableArray *_indexArray = [NSMutableArray arrayWithCapacity:([sectionIndexTitleLetters length]+2)]; 

     [_indexArray addObject:@"{search}"]; 
     [_indexArray addObject:@"#"]; 

     for (unsigned int _charIdx = 0; _charIdx < [sectionIndexTitleLetters length]; _charIdx++) { 
      char _indexChar[2] = { toupper([sectionIndexTitleLetters characterAtIndex:_charIdx]), '\0'}; 
      [_indexArray addObject:[NSString stringWithCString:_indexChar encoding:NSUTF8StringEncoding]]; 
     } 

     return _indexArray; 
    } 
    return nil; 
} 

- (NSInteger) tableView:(UITableView *)tv sectionForSectionIndexTitle:(NSString *)title atIndex:(NSInteger)index { 
    if (tv != searchDisplayController.searchResultsTableView) { 
     if (index == 0) { 
      // 
      // This is the search bar "section" 
      // 
      [currentTableView scrollRectToVisible:[[currentTableView tableHeaderView] bounds] animated:YES]; 
      return -1; 
     } 
     else if (index == 1) { 
      // 
      // This is the "#" section, which covers non-alphabetic section headers (e.g. digits 0-9) 
      // 
      return 0; 
     } 
     else { 
      // 
      // This is a bit more involved because the section index array may contain indices that do not exist in the 
      // fetched results controller's sections->name info. 
      // 
      // What we are doing here is building a "fake-index" array that will return a real section index regardless of 
      // whether the section index title being touched exists or not. 
      // 
      // The fake array will be of length of the section index title array, and each index will contain an unsigned 
      // integer from 1 to {numOfRealSections}. 
      // 
      // The value this array returns will be "nearest" to the real section that is in the fetched results controller. 
      // 

      NSUInteger _alphabeticIndex = index-2; 

      unsigned int _idxArray[26]; 
      for (unsigned int _initIdx = 0; _initIdx < [sectionIndexTitleLetters length]; _initIdx++) { 
       _idxArray[_initIdx] = [[fetchedResultsController sections] count] - 1; 
      } 

      unsigned int _previousChunkIdx = 0; 
      NSNumberFormatter *_numberFormatter = [[NSNumberFormatter alloc] init]; 
      NSLocale *_enUSLocale = [[NSLocale alloc] initWithLocaleIdentifier: @"en_US"]; 
      [_numberFormatter setLocale:_enUSLocale]; 
      [_enUSLocale release]; 

      for (unsigned int _sectionIdx = 0; _sectionIdx < [[fetchedResultsController sections] count]; _sectionIdx++) { 
       NSString *_sectionTitle = [[[fetchedResultsController sections] objectAtIndex:_sectionIdx] name]; 
       if (![_numberFormatter numberFromString:_sectionTitle]) { 
        // what's the index of the _sectionTitle across sectionIndexTitleLetters? 
        for (unsigned int _titleCharIdx = 0; _titleCharIdx < [sectionIndexTitleLetters length]; _titleCharIdx++) { 
         NSString *_titleCharStr = [[sectionIndexTitleLetters substringWithRange:NSMakeRange(_titleCharIdx, 1)] uppercaseString]; 
         if ([_titleCharStr isEqualToString:_sectionTitle]) { 
          // put a chunk of _sectionIdx into _idxArray 
          unsigned int _currentChunkIdx; 
          for (_currentChunkIdx = _previousChunkIdx; _currentChunkIdx < _titleCharIdx; _currentChunkIdx++) { 
           _idxArray[_currentChunkIdx] = _sectionIdx - 1; 
          } 
          _previousChunkIdx = _currentChunkIdx; 
          break; 
         } 
        }    
       } 
      } 

      [_numberFormatter release]; 

      return (NSInteger)_idxArray[_alphabeticIndex]; 
     } 
    } 
    return 0; 
} 
+0

嗨Alex, 感謝您的幫助。上面的代碼確實有效。但是fetchedresultscontroller部分並不如預期。例如,如果有兩個姓氏值分別爲111和222,則表中有兩個部分(一個爲1,另一個爲2)。 爲了規避這個問題,並將它們歸入「#」,我在#前面加上了以數字開頭的姓氏,同時存儲在覈心數據中。如果姓氏以表格渲染器中的#開頭,則必須剝離它。我相信這不是一個乾淨的方式來做到這一點。有沒有更好的方式來處理這與取得的結果控制器? – KSH 2010-06-07 07:52:48

+0

此外,#部分出現在「A」上方的頂部(因爲爲獲取的結果控制器指定了排序順序)。但默認聯繫人應用程序在底部顯示#也是有效的。是否有可能通過獲取結果控制器來實現這一點?或者我們應該手動編寫管理各種陣列的整個邏輯?我更喜歡抓取的結果控制器來處理內存和易用性。 – KSH 2010-06-07 08:03:00

+0

更新:我添加了另一個數字列,以指示姓是否以字母表開頭,並且先排序,然後再次排列在姓氏列上。即。兩種排序描述符產生了適當的結果(我也將#推到了索引的底部)。目前爲止工作良好,但如果應用程序使用其他語言本地化,該怎麼辦?如何檢查名稱的給定起始字母是否是標準字符集的一部分,並且在索引中可用(假設索引已本地化)。 – KSH 2010-06-07 10:21:19

1

我可能是幼稚,但我不明白爲什麼這些解決方案是如此的巴洛克式。我這樣做:

在我的模型,我添加了一個方法:

-(NSString *)lastInitial { 
    return [self.lastname substringToIndex:1]; 
} 

在我tablecontroller我設置fetchedresultscontroller使用該方法:

NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"lastInitial" cacheName:@"Master"]; 

似乎工作 - 有這是一個壞主意的原因?或者我是否從ios5中的新功能中受益?