32

I am getting an EXC-BAD-ACCESS error on this statement:

var thisPredicate = NSPredicate(format: "(sectionNumber == %@"), thisSection)

thisSection has an Int value of 1 and displays the value 1 when I hover over it. But in the debug area I see this:

thisPredicate = (_ContiguousArrayStorage ...)

Another predicate using a String shows as ObjectiveC.NSObject Why is this happening?

Cœur
  • 37,241
  • 25
  • 195
  • 267
PatriciaW
  • 893
  • 1
  • 12
  • 30
  • You have an extra opening parenthesis that should not be there – Paul.s Aug 07 '15 at 19:01
  • I'm not sure why it shows an extra parenthesis above because that is not what I have - which is: var thisPredicate = NSPredicate(format: "(sectionNumber == %@)",thisSection) – PatriciaW Aug 07 '15 at 19:14
  • @PatriciaW the problem in your question was then that you missed the closure parenthesis after **@**. Btw, I have edited my previous answer, maybe you should take a look into some considerations I have added. – Hugo Alonso Aug 07 '15 at 19:44
  • Hugo, I corrected my code in the comment above but I did not edit it ... which I will do now. – PatriciaW Aug 08 '15 at 15:47

3 Answers3

45

You will need to change %@ for %i and remove the extra parenthesis:

Main problem here is that you are putting an Int where it's expecting an String.

Here's an example based on this post:

class Person: NSObject {
    let firstName: String
    let lastName: String
    let age: Int

    init(firstName: String, lastName: String, age: Int) {
        self.firstName = firstName
        self.lastName = lastName
        self.age = age
    }

    override var description: String {
        return "\(firstName) \(lastName)"
    }
}

let alice = Person(firstName: "Alice", lastName: "Smith", age: 24)
let bob = Person(firstName: "Bob", lastName: "Jones", age: 27)
let charlie = Person(firstName: "Charlie", lastName: "Smith", age: 33)
let quentin = Person(firstName: "Quentin", lastName: "Alberts", age: 31)
let people = [alice, bob, charlie, quentin]


let thisSection = 33
let thisPredicate = NSPredicate(format: "age == %i", thisSection)

let _people = (people as NSArray).filteredArrayUsingPredicate(thisPredicate)
_people

Another workaround would be to make thisSection's value an String, this can be achieved by String Interpolation or via description property of the Int.. lets say:

Changing:

let thisPredicate = NSPredicate(format: "age == %i", thisSection)

for

let thisPredicate = NSPredicate(format: "age == %@", thisSection.description)

or

let thisPredicate = NSPredicate(format: "age == %@", "\(thisSection)")

of course, you can always bypass this step and go for something more hardcoded (but also correct) as:

let thisPredicate = NSPredicate(format: "sectionNumber == \(thisSection)")

But take into account that for some weird reason String Interpolation (this kind of structure: "\(thisSection)") where leading to retain cycles as stated here

Community
  • 1
  • 1
Hugo Alonso
  • 6,684
  • 2
  • 34
  • 65
  • Hugo, thanks for these suggestions. I tried %@ but did not know to use .description. I had tried %d but not %i. – PatriciaW Aug 08 '15 at 15:53
  • `.description` is a property of every data type in **Swift**, it turns value of `Number`, `Date`, etc into it's `String` representation. `%i` do this conversion for you. – Hugo Alonso Aug 10 '15 at 15:53
  • 2
    Spend two days to figure out why my fetchedresultcontroller with predicate isn't working, and the solution was replacing `%@` with `%i`. Data types are important, we need to make sure that we are filtering with the right type!!! – lionserdar Oct 02 '18 at 16:05
  • This won't work if the value is an int64 %I will convert treat it as an int32 and if the value is above 2,147,483,648 it will overflow. – Mycroft Canner Jan 10 '20 at 14:58
34

When your data is safe or sanitized, you might try String Interpolation Swift Standard Library Reference. That would look something like this:

let thisSection = 1
let thisPredicate = NSPredicate(format: "sectionNumber == \(thisSection)")
Cœur
  • 37,241
  • 25
  • 195
  • 267
Mr Beardsley
  • 3,743
  • 22
  • 28
  • 5
    Please don't ever use String Interpolation when creating a predicate. This answer: https://stackoverflow.com/a/31885149/543844, provided by Hugo Alonso should be selected as the correct answer. – dbDev Sep 24 '19 at 02:57
2

On 64 bit architecture an Int maps to an Int64 and %i will overflow if its value is greater than 2,147,483,648.

You will need to change %@ for %ld and remove the extra parenthesis.

Mycroft Canner
  • 1,828
  • 1
  • 11
  • 24