2014-10-16 2 views
70

Я пытаюсь фильтровать массив в соответствии с одним из его строковых полей.NSString containsString crashes

Оба nameLower и filterLower имеет значение NSString внутри, и все же я получаю:

__NSCFString containsString:]: unrecognized selector sent to instance 0x7f876b79e160 

-(void) filterFriendsArray:(NSString*)filter { 
    [_filteredFriendsArray removeAllObjects]; 
    for (FacebookUser* user in _friendsArray) 
    { 
     NSString* nameLower = [user.user.name lowercaseString]; 
     NSString* filterLower = [filter lowercaseString]; 
     if ([nameLower containsString:filterLower]) 
      [_filteredFriendsArray addObject:user]; 
    } 
    _displayedFriendsArray = _filteredFriendsArray; 
} 
+46

Вы работаете на iOS ниже 8? Метод 'containsString:' был добавлен только в iOS 8. –

+6

Любопытно, что 'containsString:' не документируется в Интернете. –

+0

@IanMacDonald вы правы .. опубликуйте его как ответ, чтобы я мог его принять. –

ответ

118

Если вы хотите, чтобы ваш код работать на прошивке 7, а также прошивке 8 вы должны использовать один из rangeOfString вызовов вместо , В принципе, если возвращаемый диапазон имеет длину 0, подстроки там нет.

/* These methods return length==0 if the target string is not found. So, to check for containment: ([str rangeOfString:@"target"].length > 0). Note that the length of the range returned by these methods might be different than the length of the target string, due composed characters and such. 
*/ 
- (NSRange)rangeOfString:(NSString *)aString; 
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask; 
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange; 
- (NSRange)rangeOfString:(NSString *)aString options:(NSStringCompareOptions)mask range:(NSRange)searchRange locale:(NSLocale *)locale NS_AVAILABLE(10_5, 2_0); 

Очевидно, что это просто реализовать containsString себя в категории с использованием rangeOfString:

@implementation NSString (Contains) 

- (BOOL)myContainsString:(NSString*)other { 
    NSRange range = [self rangeOfString:other]; 
    return range.length != 0; 
} 

@end 
+0

на osx rangeOfString, кажется, возвращает nil, а не 0, если строка не содержится –

+2

// «on osx rangeOfString, кажется, возвращает ноль, а не 0, если строка не содержится» Последний раз, когда я проверил, nil была равна нулю. – w0mbat

+5

было бы так приятно видеть эту проблему во время компиляции – user230910

7

сравнить rangeOfString с NSNotFound

NSRange range = [self rangeOfString:other]; 
if(range.location != NSNotFound){ 
    //do something 
} 
-1

Swift вариант ответа дается w0mbat:

extension NSString { 
    func compatibleContainsString(string: NSString) -> Bool{ 
     let range = self.rangeOfString(string as String) 
     return range.length != 0 
    } 
} 
+0

Диапазон не имеет длины члена. – lostintranslation

+0

Отредактированный мой ответ, видимо, диапазон String не содержит «длины», но NSString делает. –

3

Используйте следующее:

if (![[NSString class] respondsToSelector:@selector(containsString)]) 
    { 
     //ios 7 
     NSRange range = [mystring rangeOfString:other]; 
     if(range.location != NSNotFound){ 
      //do something 
     } 
    } 
    else //for iOS 8 
    { 
      if ([mystring containsString: other]) 
      { 
       //do something 
      }        
    } 
0

Для тех, кто столкнулся с этим в XLForm, убедитесь, что при установке XLForm используя стручки

platform :ios, '7' 
pod 'XLForm' 

Это уже зафиксировано в 3.1

от

if ([cellClassString contains:@"/"]) { 

} 

в

if ([cellClassString rangeOfString:@"/"].location != NSNotFound) { 

} 
0

Я инкапсулировать мое решение в YJKit, и вы можете назвать - [NSString containsString:] даже для старой версии, которая ниже прошивкой 8.

bool _yj_streq(const char *str1, const char *str2, size_t length) { 
    for (int i = 0; i < length; i++) { 
     if (*str1++ != *str2++) { 
      return false; 
     } 
    } 
    return true; 
} 

- (BOOL)yj_containsString:(NSString *)string { 

    NSAssert(string != nil, @"*** -[%@ containsString:] can not use nil argument.", [self class]); 

    size_t len1 = (size_t)self.length; 
    size_t len2 = (size_t)string.length; 

    if (len1 == 0 || len2 == 0 || len1 < len2) { 
     return NO; 
    } 

    const char *str1 = self.UTF8String; 
    const char *str2 = string.UTF8String; 

    for (size_t i = 0; i <= len1 - len2; i++) { 
     const char *substr1 = str1 + i; 
     if (_yj_streq(substr1, str2, len2)) { 
      return YES; 
     } else { 
      continue; 
     } 
    } 

    return NO; 
} 

Вот мой исходный код: https://github.com/huang-kun/YJKit/blob/master/YJKit/Base/Foundation/Categories/Generics/NSString%2BYJCompatible.m

+1

Хотя эта ссылка может ответить на вопрос, лучше включить здесь основные части ответа и предоставить ссылку для справки. Ответные ссылки могут стать недействительными, если связанная страница изменится. – Marusyk