How to set a Bool value of an NSManagedObject in swift 3/ iOS 10

I am upgrading my app to iOS 10 / swift 3

So constructing an

NSManagedObject
with a dictionary (values received from remote db) this way...
let writerDictionary = [
...: ...,
...: ...,
...:...
]
let newWriter = Writer(dictionary: wirterDictionary, context: shared_context)


isFavorite is an @

NSManaged
property of Writer the NSManagedObject subclass. I set isFavorite like this:
newWriter.isFavorite = true

right after constructing the

newWriter
object before saving the context.

This line crashes with Uncaught Exception "libc++abi.dylib: terminating with uncaught exception of type NSException" in iOS 10

I also tried:

newWriter.setValue(true, forKey: "isFavorite")

It doesn't crash - but the bool value doesn't change?


Previously there was no problem whatsoever with iOS 9


This is the Writer sublclass:

import UIKit
import CoreData
@objc(Writer)
class Writer: NSManagedObject {
   
    /
    @NSManaged var id: NSNumber
    @NSManaged var name: String
    @NSManaged var picture: String?
    @NSManaged var publicationID: NSNumber
    @NSManaged var language: String
    @NSManaged var country: String
    @NSManaged var lastArticle: Date
   
    @NSManaged var isFavorite: Bool           /
   
    /
    @NSManaged var hasNewArticles: Bool
    /
    @NSManaged var publication: Publication
    @NSManaged var articles: [Article]
   
    var writerImage: UIImage? {
        get {
            return ImageCache.sharedCache.imageWithIdentifier("writers-" + String(id))
        }
        set {
            ImageCache.sharedCache.storeImage(newValue, withIdentifier: "writers-" + String(id))
        }
    }
   
    override init(entity: NSEntityDescription, insertInto context: NSManagedObjectContext?) {
        super.init(entity: entity, insertInto: context)
    }
   
    init(dictionary: [String : AnyObject], context: NSManagedObjectContext) {
        let entity = NSEntityDescription.entity(forEntityName: "Writer", in: context)!
        super.init(entity: entity, insertInto: context)
       
        id = ...
        name = ...
        picture = ...
        publicationID = ...
        language = ...
        country = ...
        lastArticle = ...
    }
   
    override func prepareForDeletion() {
        if let _ = writerImage {
            writerImage = nil
        }
    }
}

Accepted Reply

The current version of Swift 3 beta seems to have some flaw about treating properties prefixed with "is".


Avoid using "is" in your property name, or if you cannot, try this:

newWriter.setValue(true, forKey: "favorite")


(Update)

Try adding @objc name to the property:

    @NSManaged @objc(isFavorite) var isFavorite: Bool

Replies

The current version of Swift 3 beta seems to have some flaw about treating properties prefixed with "is".


Avoid using "is" in your property name, or if you cannot, try this:

newWriter.setValue(true, forKey: "favorite")


(Update)

Try adding @objc name to the property:

    @NSManaged @objc(isFavorite) var isFavorite: Bool

Impossible, man!


I kinda figured this as I put a breakpoint on exception and printed $arg1 in the debugger it gave me this line

[Writer setFavorite:]: unrecognized selector sent to instance 0x7fc9144535a0

It's doing exactly what you said, creating a setter method for NSManagedObject subclass based on the name of the property...


Thanks a million...

And what code caused the exception? `newWriter.isFavorite = true`, `newWriter.setValue(true, forKey: "isFavorite") ` or `newWriter.setValue(true, forKey: "favorite")`? Or somewhere else?

Thanks for posting this workaround. This is a known issue that will be fixed in a future beta: https://github.com/apple/swift/pull/3254

I had the issue as discussed above, and using the method


newWriter.setValue(true, forKey: "favorite") -- works


However, regardless of the Boolean value it evaluations as false


For example ...


print( "object.isPending: \(object.description)" )

output: object.isPending = 1


when evaluated

if object.isPending == true

{

print( "object is true" )

}


or ... print( "value: \(object.isPending)" )


In all cases the Boolean evaluation is alwasy "false" though the value in core-data is 1 (true).


Anyone seen this? It's driving me nuts, this doesn't make sense


-gary

Sorry, but my `setValue(_:forKey:)` workaround seems to be inconsistent with internal behaviour of Core Data (NSManagedObject).


Can you try adding `@objc(isPending)` to the property and reverting the `setValue(_:forKey:)` to usual assignment?