Reputation: 776
I am doing a fetch request with a predicate mentioned in the block quote below, but I seem to get "logically false fetch request". What does this message mean and what step should I take to find the problem and resolve it?
annotation: logically false fetch request (entity: Country; predicate: ("alpha3Code" == "KOR"); sortDescriptors: ((null)); type: NSManagedObjectResultType; ) short circuits.
Here is the code that I get the error from
let record = Currency.fetch(id: currency)[0] as! Currency
where Currency class is as follows. "fetch" is implemented in NSManagedObjectProtocol trait
public class Currency: NSManagedObject, NSManagedObjectProtocol, XMLImporterDelegate {
private static let attributes = ["name", "currency", "decimalUnit", "isUsed"]
private static let xmlRecordTag = "CcyNtry"
private static let xmlAttributeTags = ["CcyNm": attributes[0],
"Ccy": attributes[1],
"CcyMnrUnts": attributes[2]]
static func setValue(managedObject: NSManagedObjectProtocol, object: Dictionary<String, Any>) {
let currency = managedObject as! Currency
currency.name = getString(from: object, withKeyValue: attributes[0])
currency.currency = getString(from: object, withKeyValue: attributes[1])
currency.decimalUnit = getInt16(from: object, withKeyValue: attributes[2])
currency.isUsed = getBool(from: object, withKeyValue: attributes[3])
return
}
static func getPredicates(forID id: Dictionary<String, Any>) -> [NSPredicate] {
var predicates: [NSPredicate] = []
predicates.append(NSPredicate.init(format: "%@ = %@", attributes[1], getString(from: id, withKeyValue: attributes[1])))
return predicates
}
func isEqual(object: NSManagedObjectProtocol) -> Bool {
if let object = object as? Currency {
if object.currency == self.currency { return false }
return true
} else {
return false
}
}
static func recordTag() -> String {
return xmlRecordTag
}
static func attribute(byTag tag: String) -> String? {
return xmlAttributeTags[tag]
}
static func getUsed() -> [Any]?{
var predicates: [NSPredicate] = []
predicates.append(NSPredicate.init(format: "%@ = %@", attributes[3], NSNumber(booleanLiteral: false)))
return fetch(predicates: predicates)
}
}
NSManagedObjectProtocol has following trait
extension NSManagedObjectProtocol {
public static func add(from objectValue: Dictionary<String, Any>) -> NSManagedObjectProtocol? {
let exists = fetch(id: objectValue)
if exists.count > 0 {
NSLog("Object already exists in CoreData : %@", objectValue.description)
return nil
} else {
return newObject(object: objectValue)
}
}
public static func addOrChange(from object: Dictionary<String, Any>) -> NSManagedObjectProtocol {
let exists = fetch(id: object)
if exists.count > 0 {
// TODO: confirm if data needs to be changed rather than delete and insert
}
delete(id: object)
return add(from: object)!
}
public static func getString(from object: Dictionary<String, Any>, withKeyValue key: String) -> String {
return object[key] as! String
}
public static func getInt16(from object: Dictionary<String, Any>, withKeyValue key: String) -> Int16 {
if let stringValue = object[key] as? String {
if let intValue = Int(stringValue) {
return Int16(intValue)
} else {
return 0
}
} else if let intValue = object[key] as? Int {
return Int16(intValue)
} else {
return 0
}
}
public static func getBool(from object: Dictionary<String, Any>, withKeyValue key: String) -> Bool {
if let boolValue = object[key] as? Bool {
return boolValue
} else {
return false
}
}
public static func fetch(predicates: [NSPredicate] = [], sortDescriptors: [NSSortDescriptor] = []) -> [Any] {
let request = Self.request(predicates: predicates)
do {
return try CoreDataHelper.getCoreDataHelper().context.fetch(request)
} catch {
return []
}
}
public static func fetch(id: Dictionary<String, Any>) -> [Any] {
return Self.fetch(predicates: Self.getPredicates(forID: id))
}
public static func delete(predicates: [NSPredicate] = []) {
let context = CoreDataHelper.getContext()
let fetchRequest = request(predicates: predicates)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)
do {
try context.execute(deleteRequest)
CoreDataHelper.getCoreDataHelper().saveContext()
} catch {
NSLog("Delete request failed")
return
}
}
public static func delete(id: Dictionary<String, Any>) {
delete(predicates: getPredicates(forID: id))
}
// MARK: - Private API
private static func newObject(object: Dictionary<String, Any>) -> NSManagedObjectProtocol {
let entityName = String(describing: self)
let context = CoreDataHelper.getContext()
let managedObject = NSEntityDescription.insertNewObject(forEntityName: entityName, into: context) as! NSManagedObjectProtocol
setValue(managedObject: managedObject, object: object)
CoreDataHelper.getCoreDataHelper().saveContext()
return managedObject
}
private static func request(predicates: [NSPredicate] = [], sortDescriptors: [NSSortDescriptor] = []) -> NSFetchRequest<NSFetchRequestResult> {
// Prepare a request
let entityName = String(describing: self)
let classObject: AnyClass! = NSClassFromString(entityName)
let objectType: NSManagedObject.Type = classObject as! NSManagedObject.Type!
let request: NSFetchRequest<NSFetchRequestResult> = objectType.fetchRequest()
// Add predicates
if predicates.count > 0 {
request.predicate = NSCompoundPredicate.init(andPredicateWithSubpredicates: predicates)
}
// Add sortDescriptors
if sortDescriptors.count > 0 {
request.sortDescriptors = sortDescriptors
}
return request
}
}
Finally this is how the CoreDataHelper looks like.
class CoreDataHelper: NSObject {
var context: NSManagedObjectContext!
var model: NSManagedObjectModel!
var coordinator: NSPersistentStoreCoordinator!
var store: NSPersistentStore!
let storeFilename = "Accounting.sqlite"
func setupCoreData() {
self.loadStore()
}
func saveContext() {
if (self.context.hasChanges) {
do {
try context.save()
} catch {
}
}
}
func applicationDocumentDictionary() -> String {
let directory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
NSLog("SQLite Directory : %@", directory)
return directory
}
func applicationStoresDirectory() -> URL {
let storesDirectory = URL.init(fileURLWithPath: self.applicationDocumentDictionary()).appendingPathComponent("Stores")
let fileManager = FileManager.default
if (!fileManager.fileExists(atPath: storesDirectory.path)) {
do {
try fileManager.createDirectory(at: storesDirectory,
withIntermediateDirectories: true,
attributes: nil)
} catch {
}
}
return storesDirectory
}
func storesURL() -> URL {
return self.applicationStoresDirectory().appendingPathComponent(storeFilename)
}
override init() {
super.init()
model = NSManagedObjectModel.mergedModel(from: nil)
coordinator = NSPersistentStoreCoordinator(managedObjectModel: model)
context = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
context.persistentStoreCoordinator = coordinator
}
func loadStore() {
if (store != nil) {
return
} else {
do {
try store = coordinator.addPersistentStore(ofType: NSSQLiteStoreType,
configurationName: nil,
at: self.storesURL(),
options: nil)
} catch {
}
}
}
static func getCoreDataHelper() -> CoreDataHelper {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.coreDataHelper
}
static func getContext() -> NSManagedObjectContext {
return getCoreDataHelper().context
}
}
Just to let you know that Country class has alpha3Code.
extension Country {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Country> {
return NSFetchRequest<Country>(entityName: "Country");
}
@NSManaged public var englishName: String?
@NSManaged public var frenchName: String?
@NSManaged public var alpha2Code: String?
@NSManaged public var alpha3Code: String?
@NSManaged public var countryNumber: Int16
}
Upvotes: 1
Views: 132
Reputation: 285082
Use the recommended format specifier %K
for a key(path) rather than %@
as described in the Predicate Documentation
predicates.append(NSPredicate.init(format: "%K = %@", attributes[1], getString(from: id, withKeyValue: attributes[1])))
Upvotes: 2