в iOS, в чистом C, это способ получить локальный путь к файлу? - PullRequest
0 голосов
/ 08 января 2019

Мне нужно получить строку cstring ... являющуюся локальным путем к файлу в комплекте.

Во-первых,

#include <CoreFoundation/CoreFoundation.h>

(что является чистым C, верно? .. Вы не можете использовать Foundation)

, а затем

CFBundleRef mb = CFBundleGetMainBundle();
CFURLRef ur = CFBundleCopyResourceURL(mb, CFSTR("blah"), CFSTR("txt"), NULL);
CFStringRef imagePath = CFURLCopyFileSystemPath(ur, kCFURLPOSIXPathStyle);

CFStringEncoding encodingMethod = CFStringGetSystemEncoding();
const char *filename = CFStringGetCStringPtr(imagePath, encodingMethod);

printf( "\n we did it! .. %s \n", filename );

Предполагая, что в вашем комплекте "blah.txt", он работает.

Это единственный способ, которым я знаю, - делать это скучно. Что за сделка?

  1. Является ли мой код скучным, анютиным глазом и жалким?

  2. Это правильная и лучшая идиома для получения пути cstring из имени файла?

(Примечание I не хочу сделать его файлом obj-c или obj-cpp. Pure C.)

1 Ответ

0 голосов
/ 09 января 2019

Ваш код на самом деле недостаточно длинный и содержит несколько мелких ошибок:

  • Вы должны CFRelease все объекты, которыми вы владеете. Возможно, вы делаете это в другом месте, но это не очевидно из кода.
  • CFStringGetCStringPtr не обещано возвращать значение. Он возвращает значение только в том случае, если строка уже хранится в нужном вам формате. Это вероятно верно в этом коде на каждой системе, на которой он, вероятно, будет работать, но это не безопасная практика CoreFoundation.
  • Аналогично, небезопасно передавать результат CFStringGetSystemEncoding в CFStringGetCStringPtr, так как последний требует 8-битного кодирования. Это не обещано, но ....
  • CFStringGetSystemEncoding почти никогда не нужен или не уместен. Вы, вероятно, на самом деле не хотите MacRoman (что вы, вероятно, получаете, если, возможно, вы не настроены на MacJapanese). Вы, вероятно, хотите UTF8, поэтому вы должны попросить об этом.

Так вот как бы вы это сделали:

CFBundleRef mb = CFBundleGetMainBundle();
CFURLRef ur = CFBundleCopyResourceURL(mb, CFSTR("blah"), CFSTR("txt"), NULL);
CFStringRef imagePath = CFURLCopyFileSystemPath(ur, kCFURLPOSIXPathStyle);

// Now convert to a C-string
CFStringEncoding encoding = kCFStringEncodingUTF8;
CFIndex length = CFStringGetLength(imagePath);
CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, encoding);

char *filename = (char *)malloc(maxSize + 1); // +1 for \0

// Technically this can fail, but it really, really can't.
CFStringGetCString(imagePath, filename, maxSize, encoding);

printf( "\n we did it! .. %s \n", filename );

// Cleanup
free(filename); filename = NULL;
CFRelease(imagePath); imagePath = NULL;
CFRelease(ur); ur = NULL;

Вам могут пригодиться функции MYStringConversion . MYCFStringCopyUTF8String возвращает вам буфер malloc (т. Е. Вам нужно free его), содержащий строку cstring. (Они взяты из главы 10 «Программирование на iOS: раздвигая границы».)

Одна боковая нота о строковых буферах. Люди часто испытывают желание использовать буферы на основе PATH_MAX. Имейте в виду, что macOS разрешает пути с именами намного длиннее, чем PATH_MAX. Я не знаю каких-либо жестких ограничений на длину строки пути macOS. На практике немногие реальные пути превышают PATH_MAX, но когда вы создаете их, интересно (а на самом деле не интересно) видеть, сколько программ ломается.

Обратите внимание, что, как правило, этот код не нужен. В большинстве проектов CoreFoundation вы просто используете ur напрямую, и это довольно приятно по сравнению с работой с необработанными cstrings.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...