NSString enthältString-Abstürze


70

Ich versuche, ein Array nach einem seiner Zeichenfolgenfelder zu filtern.

Sowohl nameLower als auch filterLower haben einen NSString-Wert im Inneren, und dennoch bekomme ich immer wieder:

__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
Laufen Sie mit einem iOS unter 8? Die containsString:Methode wurde nur in iOS 8 hinzugefügt.
Ian MacDonald

6
Es ist merkwürdig, dass containsString:nicht online dokumentiert ist.
Hot Licks

@ IanMacDonald du hast recht .. poste es als Antwort, damit ich es akzeptieren kann ..
Asaf Nevo

@HotLicks Nach all dieser Zeit immer noch nicht dokumentiert.
user3344977

Antworten:


119

Wenn Sie möchten, dass Ihr Code sowohl unter iOS 7 als auch unter iOS 8 funktioniert, sollten Sie stattdessen einen der rangeOfString-Aufrufe verwenden. Wenn der zurückgegebene Bereich eine Länge von Null hat, ist der Teilstring grundsätzlich nicht vorhanden.

/* 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);

Offensichtlich ist es trivial, sich mit rangeOfString in einer Kategorie zu implementieren.

@implementation NSString (Contains)

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

@end

auf osx rangeOfString scheint null und nicht 0 zurückzugeben, wenn die Zeichenfolge nicht enthalten ist
Morten J

2
// "on osx rangeOfString scheint nil und nicht 0 zurückzugeben, wenn die Zeichenfolge nicht enthalten ist." Als ich das letzte Mal nachgesehen habe, war nil gleich Null.
w0mbat

5
Es wäre so schön, dieses Problem zur Kompilierungszeit zu sehen
user230910

2
Gemäß der Apple-Dokumentation sollten Sie das Ergebnis mit NSNotFoundanstelle von 0oder vergleichen nil.
Christoffer Årstrand

4
Ja, überprüfen Sie den Standort des Bereichs für NSNotFound -return range.location != NSNotFound;
johnpatrickmorgan

8

Vergleichen Sie rangeOfString mit NSNotFound

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

3

Verwenden Sie Folgendes:

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

Stellen Sie für diejenigen, die dies in XLForm festgestellt haben, sicher, dass Sie bei der Installation XLFormmit Pods arbeiten

platform :ios, '7'
pod 'XLForm'

Es ist bereits behoben in 3.1

von

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

}

zu

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

}

0

Ich kapsle meine Lösung in YJKit und Sie können - [NSString enthältString:] auch für alte Versionen unter iOS 8 aufrufen.

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

Hier ist mein Quellcode: https://github.com/huang-kun/YJKit/blob/master/YJKit/Base/Foundation/Categories/Generics/NSString%2BYJCompatible.m


1
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert.
Roman Marusyk

-1

Schnelle Version der Antwort von w0mbat:

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

Der Bereich hat keine Elementlänge.
Verlorene Übersetzung

Meine Antwort wurde bearbeitet. Anscheinend enthält String's Range keine "Länge", NSString jedoch.
Chris C
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.