Używanie predykatu w Swift

94

Pracuję tutaj nad samouczkiem (uczę się języka Swift) dla mojej pierwszej aplikacji: http://www.appcoda.com/search-bar-tutorial-ios7/

Utknąłem w tej części (kod Objective-C):

- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"name contains[c]         %@", searchText];
    searchResults = [recipes filteredArrayUsingPredicate:resultPredicate];
}

Czy ktoś może doradzić, jak stworzyć odpowiednik dla NSPredicate w Swift?

levitatejay
źródło

Odpowiedzi:

158

To naprawdę jest tylko przełącznik składni. OK, mamy więc wywołanie metody:

[NSPredicate predicateWithFormat:@"name contains[c] %@", searchText];

W Swift konstruktory pomijają część „blahWith…” i po prostu używają nazwy klasy jako funkcji, a następnie przechodzą bezpośrednio do argumentów, tak [NSPredicate predicateWithFormat: …]by się stało NSPredicate(format: …). (Na innym przykładzie [NSArray arrayWithObject: …]będzie to NSArray(object: …). Jest to normalny wzorzec w języku Swift).

Więc teraz musimy tylko przekazać argumenty do konstruktora. W Objective-C literały NSString wyglądają jak @"", ale w Swift używamy po prostu cudzysłowów dla łańcuchów. To daje nam:

let resultPredicate = NSPredicate(format: "name contains[c] %@", searchText)

I faktycznie tego właśnie tutaj potrzebujemy.

(Nawiasem mówiąc, zauważysz, że niektóre inne odpowiedzi zamiast tego używają ciągu formatu, takiego jak "name contains[c] \(searchText)". To nie jest poprawne. To używa interpolacji ciągów, która różni się od formatowania predykatów i generalnie nie działa w tym przypadku).

Gdakanie
źródło
Dzięki. Uratujesz mnie pewnego dnia!
Hugo,
2
Aby odnieść się do drugiej linii metody, możesz użyć predykatu jako:searchResults = recipes.filter { resultPredicate.evaluateWithObject($0) }
Ben Packard
44

Pracuję z predykatem przez dość długi czas. Oto mój wniosek (SWIFT)

//Customizable! (for me was just important if at least one)
request.fetchLimit = 1


//IF IS EQUAL

//1 OBJECT
request.predicate = NSPredicate(format: "name = %@", txtFieldName.text)

//ARRAY
request.predicate = NSPredicate(format: "name = %@ AND nickName = %@", argumentArray: [name, nickname])


// IF CONTAINS

//1 OBJECT
request.predicate = NSPredicate(format: "name contains[c] %@", txtFieldName.text)

//ARRAY
request.predicate = NSPredicate(format: "name contains[c] %@ AND nickName contains[c] %@", argumentArray: [name, nickname])
Jiří Zahálka
źródło
1
Co jest równe LIKE 'a%z'?
TomSawyer
@ Jiří Zahálka Co to jest prośba o wysłuchanie?
Muju
28

Przykład użycia w Swift 2.0

let dataSource = [
    "Domain CheckService",
    "IMEI check",
    "Compliant about service provider",
    "Compliant about TRA",
    "Enquires",
    "Suggestion",
    "SMS Spam",
    "Poor Coverage",
    "Help Salim"
]
let searchString = "Enq"
let predicate = NSPredicate(format: "SELF contains %@", searchString)
let searchDataSource = dataSource.filter { predicate.evaluateWithObject($0) }

Otrzymasz (plac zabaw)

wprowadź opis obrazu tutaj

gbk
źródło
A co, jeśli ... Jeśli mam szereg słowników? Jak mogę przeanalizować, aby uzyskać dane?
Revathy Durairajan
1
@RevathyDurairajan potrzebujesz SELF.yourkeyname do filtrowania tablicy słowników.
Pawan Rai
11

Możesz użyć filtrów dostępnych w swift, aby odfiltrować zawartość z tablicy zamiast używać predykatu, takiego jak w Objective-C.

Przykład w Swift 4.0 jest następujący:

var stringArray = ["foundation","coredata","coregraphics"]
stringArray = stringArray.filter { $0.contains("core") }

W powyższym przykładzie, ponieważ każdy element tablicy jest łańcuchem, możesz użyć containsmetody do filtrowania tablicy.

Jeśli tablica zawiera obiekty niestandardowe, właściwości tego obiektu można wykorzystać do podobnego filtrowania elementów.

Gurunath Sripad
źródło
5

Użyj poniższego kodu:

 func filterContentForSearchText(searchText:NSString, scopes scope:NSString)
{
    //var searchText = ""

    var resultPredicate : NSPredicate = NSPredicate(format: "name contains[c]\(searchText)", nil)

    //var recipes : NSArray = NSArray()

    var searchResults = recipes.filteredArrayUsingPredicate(resultPredicate)
}
PREMKUMAR
źródło
1
Z jakiegoś powodu pisanie tego w ten sposób nie zadziałało, ale zrobienie tego, aby myPredicateString = "name zawiera [c] (searchText)", a następnie zrobienie var resultPredicate: NSPredicate = NSPredicate (format: myPredicateString)
działało
5

Myślę, że byłby to lepszy sposób na zrobienie tego w Swift:

func filterContentForSearchText(searchText:NSString, scope:NSString)
{
   searchResults = recipes.filter { name.rangeOfString(searchText) != nil  }
}
Harris
źródło
1
Jest to bardziej idiomatyczne, jeśli filtrujesz a Sequence, ale są przypadki, w których będziesz potrzebować a NSPredicate, np NSFetchedResultsController.
Jarsen,
1

W szybkim 2.2

func filterContentForSearchText(searchText: String, scope: String) {
    var resultPredicate = NSPredicate(format: "name contains[c]         %@", searchText)
    searchResults = (recipes as NSArray).filteredArrayUsingPredicate(resultPredicate)
}

W Swift 3.0

func filterContent(forSearchText searchText: String, scope: String) {
        var resultPredicate = NSPredicate(format: "name contains[c]         %@", searchText)
        searchResults = recipes.filtered(using: resultPredicate)
    }
Saranjith
źródło
1

// zmień "nazwę" i "wartość" zgodnie z danymi twojej tablicy.

// Zmień nazwę "yourDataArrayName" zgodnie z twoją tablicą (NSArray).

    let resultPredicate = NSPredicate(format: "SELF.name contains[c] %@", "value")

    if let sortedDta = yourDataArrayName.filtered(using: resultPredicate) as? NSArray {

 //enter code here.

        print(sortedDta)
    }
Hitesh Chauhan
źródło