Подтвердить что ты не робот

Как реализовать этот многострочный строковый литерал в Swift?

В моем коде Objective-C для моей рамки GPUImage у меня есть следующий макрос:

#define STRINGIZE(x) #x
#define STRINGIZE2(x) STRINGIZE(x)
#define SHADER_STRING(text) @ STRINGIZE2(text)

который позволяет мне встраивать многострочные вершинные и фрагментарные шейдеры как литералы NSString в мои подклассы пользовательского фильтра, например:

NSString *const kGPUImagePassthroughFragmentShaderString = SHADER_STRING
(
 varying highp vec2 textureCoordinate;

 uniform sampler2D inputImageTexture;

 void main()
 {
     gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
 }
);

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

Swift устраняет макросы компилятора, и в документации говорится об этом:

Сложные макросы используются в C и Objective-C, но не имеют аналогов в Свифт. Сложные макросы - это макросы, которые не определяют константы, включая скобки, функциональные макросы. Вы используете сложные макросы в C и Objective-C, чтобы избежать ограничений проверки типов или избежать переименование большого количества кода шаблона. Однако макросы могут отладки и реорганизации. В Swift вы можете использовать функции и дженериков для достижения тех же результатов без каких-либо компромиссов. Поэтому сложные макросы, которые находятся в C и Objective-C источнике файлы не доступны для вашего кода Swift.

В строке "В Swift вы можете использовать функции и обобщения для достижения тех же результатов без каких-либо компромиссов", есть ли способ в Swift предоставить многострочные строковые литералы, не прибегая к последовательности операций конкатенации?

4b9b3361

Ответ 1

Насколько я знаю, все еще недоступны многострочные строки Alas Swift. Однако при проведении некоторых исследований по этому вопросу я нашел обходное решение, которое может быть полезно. Это сочетание этих элементов:

Настройка автоматической службы

Используя Automator, вы можете настроить дополнительный сервис со следующими свойствами:

  • Единственное действие "Run Shell Script"
  • Отметьте "Выход заменяет выделенный текст"
  • Измените оболочку на /usr/bin/perl
  • Добавьте выдержку кода ниже в окно действия
  • Сохранить как нечто вроде "Заменить с помощью цитированного быстрого многострочного соединения"

Выдержка кода

print "\"\\n\".join([\n";   # Start a join operation

# For each line, reformat and print
while(<>) {
  print "    ";         # A little indentation 
  chomp;                # Loose the newline
  s/([\\\"])/\\$1/g;    # Replace \ and " with escaped variants
  print "\"$_\"";       # Add quotes around the line 

  print "," unless eof  # Add a comma, unless it is the last line
  print "\n";           # End the line, preserving original line count
 }

print "  ])"; # Close the join operation

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

  • Я использовал версию "\n".join(...) для создания многострочной строки, вы можете использовать ответ расширения из Swift - Разделить строку на несколько строк или даже + вариант, я оставлю это как упражнение для пользователя
  • Я выбрал небольшой отступ с пробелами и заменил \ и ", чтобы сделать его немного более прочным
  • Комментарии, конечно, необязательны, и вы, вероятно, можете немного сократить код. Я попытался выбрать ясность и удобочитаемость.
  • Код, как есть, сохраняет пробелы, но вы можете отредактировать, если это не требуется. Также оставлено в качестве упражнения для пользователя.

Использование службы

Откройте свою игровую площадку или редактор кода и вставьте/напишите несколько текстовых файлов:

  • Отметить текстовый блок
  • Выполнить Xcode (или аналогичный) > Сервисы > Заменить с помощью цитированного быстрого многострочного соединения

Теперь у вас есть многострочная строка в правильной быстрой кодировке. Вот пример до и после текста:

Here is my multiline text 
example with both a " and
a \ within the text

"\n".join([
    "Here is my multiline text ",
    "example with both a \" and",
    "a \\ within the text"
  ])

Ответ 2

Похоже, ваша конечная цель - избегать использования автономных файлов шейдеров?

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

Включите результирующий файл .swift в свой проект, и у вас нет штрафа за выполнение, а еще проще отладки, если вы хорошо сгенерируете код.

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