Core Data fetch exception

coredata

#1

Доброго времени суток!

Есть такой код. Поля exportLockIdQ нет в Entity2. Fetch завернут в try, но вместо того чтобы зайти в catch вываливается sigabrt. Объясните плизь такое поведение.

    let context = self.fetchedResultsController.managedObjectContext
    var result: [Entity2] = []
    let predicate = NSPredicate(format: "exportLockIdQ != nil")  //Такого поля нет
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: String(describing: Entity2.self))

    if (predicate != nil) {
        request.predicate = predicate
    }
    do{
        result = try context.fetch(request) as! [Entity2]
    }
    catch let error {
        let q = 0
        fatalError("fatalError")
    }

#2

Попробуйте так:

let request: NSFetchRequest<Entity2> = Entity2.fetchRequest()
request.predicate = NSPredicate(format: "exportLockIdQ != nil")

var result: [Entity2] = []
do {
    result = try context.fetch(request)
} catch {
    print(error)
}
print(result)

#3

И так тоже не работает.
Проблема в том, что в секцию catch даже не заходит.


#4

Удалите приложение из симулятора. Entity2 вы создавали этот класс или его Xcode генерирует?


#5
  1. Удалял - не помогает
  2. и руками создавал и xcode генерил - результат один -
    Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: 'keypath exportLockIdQ not found in entity ’

Просто не понятно накой черт там try если он все равно не отрабатывает, и приложуха рушится.
Кстати если в строке

let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Entity2")//String(describing: Entity2.self))

указать вообще левое entityName, то try также не отработает.

В свифте совсем недавно и возможно я что не так делаю, но такое поведение try, мягко говоря озадачивает.


#6

У вас в сущности нет атрибута с именем exportLockIdQ.

Он не может магическим способом отлавливать ошибки которые вне инструкции do-catch, или вообще не в коде, как у вас.


#7
  1. Ну какбе было написанно что поля exportLockIdQ впринципе нет
  2. Что значит вне инструкции do-catch?
  3. Таки а где ошибка если не в коде?
  4. Пробуем обратится к документации (документация) читаем:
    error
    If there is a problem executing the fetch, upon return contains an instance of NSError that describes the problem.

Return Value
An array of objects that meet the criteria specified by request fetched from the receiver and from the persistent stores associated with the receiver’s persistent store coordinator. If an error occurs, returns nil. If no objects match the criteria specified by request, returns an empty array.

Handling Errors in Swift:
In Swift, this method returns a nonoptional result and is marked with the throws keyword to indicate that it throws an error in cases of failure.
You call this method in a try expression and handle any errors in the catch clauses of a do statement, as described in Error Handling in The Swift Programming Language (Swift 4) and Error Handling in Using Swift with Cocoa and Objective-C (Swift 4).

т.е. как бы предпологается что может возникнуть ошибка которую можно обработать. Ан нет приложуха падает с sigabrt.

Даже если написать так let qresult = try? context.fetch(request), то тоже падение с sigabrt, хотя предпологается что если возникает ошибка то прото в qresult упадет nil.

  1. Попробуйте в C# или Java задать неправильное поле, обернуть все в секцию try и вы будете приятно удивлены что вывалится ошибка и попадет в секцию catch.

#8

Вы проверяете != nil и ваше “поля нет” я расценил что оно может быть nil.

Исключение выкидывает NSException, до обработки do-catch даже дело не доходит, примерно так:

enum MyError: Error {
    case fatal
}

func getProperty() {
    let exception = NSException(name: NSExceptionName(rawValue: "Test"), reason: "Test", userInfo: nil)
    exception.raise()
}

func test() throws {
    getProperty()
    throw MyError.fatal
}

do {
    try test()
} catch {
    print(error)
}

При компиляции Xcode из xcdatamodeld создает архив классов, который приложение разархивирует в реальные классы. А все атрибуты указанные в сущности превращаются в свойства класса, при этом вы не пишите код, по этому ошибка не в коде :slight_smile: Хотя на самом деле конечно в коде “exportLockIdQ != nil” вы пытаетесь обратится к несуществующему свойству, от этого и выскакивает исключение.

CoreData написан на Objc а в нём ошибки обрабатываются с помощью NSException (точнее даже, критические ошибки - исключения), просто нужно это знать.

P.S. Интерпретируемые языки это мусор.


#9

Насколько я понял все дело в том что swift не отлавливает ошибки пришедшие от object-c, т.е. NSException.
Разве это не странно?

Решение проблемы описанно Тут + можно юзать SwiftTryCatch

P.S. не нравится Java/C# давайте глянем на проваславный c++: что думаете вернет этот код?

#include <iostream>

using namespace std;

void throwError(){
     throw std::invalid_argument( "received negative value" );
}

void test() {
    throwError();
    cout<<"test_Ok";
}

int main() {
	try{
	    test();
	    cout<<"main_Ok";
	}
	catch(...){
	    cout<<"main_error";
	}
}

Правильно “main_error” и не упадет. Проверить можно тут - http: //jdoodle.com/a/6MJ


#10

try-catch в Objc работает совершенно по другому, может оно и странно, но тут ничего не поделаешь. Если вам сильно важно отлавливать exceptions вы всегда можете создать Bridging Header и обернуть try-catch:

#import <Foundation/Foundation.h>

typedef void (^TryBlock)(void);
typedef void (^CatchBlock)(NSException *e);
typedef void (^FinallyBlock)(void);

extern inline void trycatch(TryBlock tBlock, CatchBlock cBlock, FinallyBlock fBlock) {
    @try {
        tBlock();
    }
    @catch (NSException *e) {
        cBlock(e);
    }
    @finally {
        fBlock();
    }
}

И тогда всё будет отлавливаться :slight_smile: