Как обрабатывать нестандартные символы Unicode в CoreData?

Один материал, который я прочитал в Интернете, - это

Rameeee! 👯👯

Поэтому он использует нестандартный символ.

Я попытался сохранить это в coredata​​p >

   NSManagedObjectContext * parentMoc = [self managedObjectContextMainContext]; //Main parent is not nsmainqueueconcurency type. Hence, this is save
    [parentMoc performBlockAndWait:^{
        if (![parentMoc save:&error])
        {
            CLog(@"Error in Saving %@", error);// handle error
        }
    }];
    NSAssert(error==nil, @"Error must be nill");

Я получил эту ошибку:

(lldb) po error
domain: @"NSCocoaErrorDomain" - code: 1671

Хм... что мне делать?

Ответ 1

Код ошибки 1671 не документирован. Однако коды ошибок 1660, 1670 и 1680 связаны с ошибками проверки строки. Так что посмотрим, что мы можем найти...

Действительные строки работают одинаково независимо от того, есть ли у них Emoji или что-то еще. Пока строка содержит только допустимые символы, никакого специального лечения не требуется. Строка, которая вызвала этот вопрос, как указано, соответствует этому описанию. Этот код работает, и изменения сохраняются без ошибок:

NSString *testNSString = @"Rameeee! 👯👯";
[newManagedObject setValue:testNSString forKey:@"name"];

Полное круглое путешествие работает точно так, как ожидалось, даже отображая корректно в UILabel в ячейке просмотра текста.

enter image description here

В результате ясно, что исходный вопрос где-то оставляет важные детали, потому что правильный ответ заключается в том, что вы не делаете ничего особенного для обработки этих символов, они просто работают.

Пример строки из @DevFly предоставляет ключ:

"\U05d4\U05d4\U05d9\U05ea\U05e8\U05d2\U05e9\U05d5\U05ea \U05db\U05dc \U05db\U05da \U05d2\U05d3\U05d5\U05dc\U05d4 \Ud83d"

Фактически вы не можете построить строковый литерал с этим содержимым без каких-либо существенных трудностей. Компилятор жалуется, что последний символ \Ud83d является "недопустимым универсальным символом", и компиляция завершается с ошибкой. Взглянув на соответствующую кодовую диаграмму из unicode.org, подтверждает следующее: \Ud83d находится в "области высоких суррогатов", и на диаграмме отмечается, что

Изолированные суррогатные коды не имеют никакой интерпретации; следовательно, для этого диапазона не предусмотрены кодовые диаграммы символов или списки имен.

Что все это значит, что \Ud83d не является допустимым символом Юникода. Он не представляет никакого символа и не может быть преобразован в кодировки, такие как UTF-8.

Если вы отбрасываете недопустимый символ с конца, то, как и выше, он работает нормально без специальной обработки:

char *testString = "\u05d4\u05d4\u05d9\u05ea\u05e8\u05d2\u05e9\u05d5\u05ea \u05db\u05dc \u05db\u05da \u05d2\u05d3\u05d5\u05dc\u05d4";
NSString *testNSString = [NSString stringWithUTF8String:testString];
[newManagedObject setValue:testNSString forKey:@"name"];

Это экономит без ошибок и снова совершает полное округление и отображается правильно в UILabel:

enter image description here

Что все это значит:

  • Эта ошибка означает, что вы каким-то образом создаете строку, содержащую недопустимые байты, которые не представляют никакого символа.
  • Это не потому, что символы являются Юникодом, потому что правильный Юникод в порядке. Но не каждое числовое шестнадцатеричное значение представляет символ Юникода, поэтому возможно иметь поврежденное значение, которое нельзя использовать в строке.
  • Поскольку ни @JimThio, ни @DevFly, ни @SharenEayrs, похоже, не хотят объяснять, как они создали свои проблемные байтовые векторы (я не могу называть их "нитями" ), невозможно сказать, что изначально вызвало проблему. Но данные повреждены, период, и он выглядит только как проблема с основными данными, потому что там, где вы используете данные.
  • Вероятная причина в том, что в какой-то момент эти строки были изменены в коде без учета того, что не каждый символ использует одинаковое количество байтов. Выполнение таких вещей, как изменение строк, основанных на символьных индексах, может вызвать проблемы. Возможно, было бы полезно рассмотреть Apple "Персонажи и Графемные кластеры" и, возможно, NSHipster статьи о типе кодировок.
  • @mmarkov предлагает использовать NSData может работать, но, вероятно, нет, если вы не прибегаете к причудливому коду, где вы вообще не используете эти байты в строке (например, вы не используете dataUsingEncoding: для преобразования в NSData). Даже если это произойдет, вы все равно будете иметь поврежденные данные, и это укусит вас рано или поздно.

Обновить, связанную с строкой, указанной в комментарии:

NSString *testNSString = @"👦🏻 👧🏻 👨🏻 👩🏻 👮🏻 👰🏻 👱🏻 👲🏻 👳🏻 👴🏻 👵🏻 👶🏻 👷🏻 👸🏻 💂🏻 👼🏻 🎅🏻 🙇🏻 💁🏻 🙅🏻 🙆🏻 🙋🏻 🙎🏻 🙍🏻 💆🏻 💇🏻 💅🏻 👂🏻 👃🏻 👋🏻 👍🏻 👎🏻 ☝🏻 👆🏻 👇🏻 👈🏻 👉🏻 👌🏻 ✌🏻 👊🏻 ✊🏻 ✋🏻 💪🏻 👐🏻 🙌🏻 👏🏻 🙏🏻";
[newManagedObject setValue:testNSString forKey:@"name"];

Снова это сохраняется без ошибок и возвращается к интерфейсу позже, как показано выше, в том числе после убийства приложения и повторного запуска. Если это как-то ломается, это не основные данные, которые его разлагают.

Ответ 2

NSCocoaErrorDomain ошибки с кодами между 1024 и 2048 являются ошибками проверки. Одно из правил проверки, которые были установлены в модели, не проходит.