98

I'm working through the tutorial here (learning Swift) for my first app: http://www.appcoda.com/search-bar-tutorial-ios7/

I'm stuck on this part (Objective-C code):

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

Can anyone advise how to create an equivalent for NSPredicate in Swift?

DavidJ
  • 4,369
  • 4
  • 26
  • 42
levitatejay
  • 1,278
  • 1
  • 9
  • 14

8 Answers8

167

This is really just a syntax switch. OK, so we have this method call:

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

In Swift, constructors skip the "blahWith…" part and just use the class name as a function and then go straight to the arguments, so [NSPredicate predicateWithFormat: …] would become NSPredicate(format: …). (For another example, [NSArray arrayWithObject: …] would become NSArray(object: …). This is a regular pattern in Swift.)

So now we just need to pass the arguments to the constructor. In Objective-C, NSString literals look like @"", but in Swift we just use quotation marks for strings. So that gives us:

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

And in fact that is exactly what we need here.

(Incidentally, you'll notice some of the other answers instead use a format string like "name contains[c] \(searchText)". That is not correct. That uses string interpolation, which is different from predicate formatting and will generally not work for this.)

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • 2
    To address the second line of your method, you might use the predicate as: `searchResults = recipes.filter { resultPredicate.evaluateWithObject($0) }` – Ben Packard May 18 '15 at 13:01
48

Working with predicate for pretty long time. Here is my conclusion (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
  • 8,070
  • 2
  • 21
  • 17
28

Example how to use in 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) }

You will get (playground)

enter image description here

hbk
  • 10,908
  • 11
  • 91
  • 124
12

You can use filters available in swift to filter content from an array instead of using a predicate like in Objective-C.

An example in Swift 4.0 is as follows:

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

In the above example, since each element in the array is a string you can use the contains method to filter the array.

If the array contains custom objects, then the properties of that object can be used to filter the elements similarly.

Anh Pham
  • 2,108
  • 9
  • 18
  • 29
Gurunath Sripad
  • 1,308
  • 2
  • 14
  • 24
6

Use The Below code:

 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
  • 8,283
  • 8
  • 28
  • 51
  • 1
    For some reason writing it like that didn't work for me however doing let myPredicateString = "name contains[c]\(searchText)" and then doing var resultPredicate : NSPredicate = NSPredicate(format:myPredicateString) did – AppHandwerker Jul 23 '14 at 15:29
5

I think this would be a better way to do it in Swift:

func filterContentForSearchText(searchText:NSString, scope:NSString)
{
   searchResults = recipes.filter { name.rangeOfString(searchText) != nil  }
}
Elijah
  • 8,381
  • 2
  • 55
  • 49
  • 1
    This is more idiomatic if you're filtering a `Sequence`, but there are cases where you will need a `NSPredicate`, like when dealing with `NSFetchedResultsController`. – Jarsen Jul 08 '15 at 20:24
1

In swift 2.2

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

In swift 3.0

func filterContent(forSearchText searchText: String, scope: String) {
        var resultPredicate = NSPredicate(format: "name contains[c]         %@", searchText)
        searchResults = recipes.filtered(using: resultPredicate)
    }
Saranjith
  • 11,242
  • 5
  • 69
  • 122
1

// change "name" and "value" according to your array data.

// Change "yourDataArrayName" name accroding to your array(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
  • 1,520
  • 15
  • 16