Конвертировать NSArray в CFStringRef *

Мне нужен способ конвертировать NSArray в нулевой завершенный список, совместимый с параметром аргументов DADiskMountWithArguments.

В документации указан параметр аргумента, который должен быть "завершенным нулевым списком" типа CFStringRef arguments[],

Я создал метод Mount, которому я хочу передать NSArray с аргументами, и в моем методе мне нужно преобразовать NSArray в CFStringRef *.

Я пробовал себя, но у меня всегда были проблемы с ARC, и я пока не смог найти хорошего способа сделать это.

Я посмотрел на проект Disk-Arbitrator в GitHub https://github.com/aburgh/Disk-Arbitrator/blob/master/Source/Disk.m для вдохновения, и создатель этого приложения использует этот метод:

- (void)mountAtPath:(NSString *)path withArguments:(NSArray *)args
{
    NSAssert(self.isMountable, @"Disk isn't mountable.");
    NSAssert(self.isMounted == NO, @"Disk is already mounted.");

    self.isMounting = YES;

    Log(LOG_DEBUG, @"%s mount %@ at mountpoint: %@ arguments: %@", __func__, BSDName, path, args.description);

    // ensure arg list is NULL terminated
    id *argv = calloc(args.count + 1, sizeof(id));

    [args getObjects:argv range:NSMakeRange(0, args.count)];

    NSURL *url = path ? [NSURL fileURLWithPath:path.stringByExpandingTildeInPath] : NULL;

    DADiskMountWithArguments((DADiskRef) disk, (CFURLRef) url, kDADiskMountOptionDefault,
                         DiskMountCallback, self, (CFStringRef *)argv);

    free(argv);
}

Но это не разрешено в ARC, и я не могу найти способ сделать это.

Обновление для лучшей наглядности:

Эта строка:

id *argv = calloc(args.count + 1, sizeof(id));

Выдает следующее сообщение об ошибке:

Неявное преобразование типа указателя не Objective C 'void *' в '__strong id *' запрещено с ARC

Указатель на неконстантный тип 'id' без явного владельца.

Чтобы исправить это, я пытаюсь сделать это:

id argv = (__bridge id)(calloc(args.count + 1, sizeof(id)));

Тогда эта строка:

[args getObjects:argv range:NSMakeRange(0, args.count)];

Выдает следующие ошибки:

[ОШИБКА] Неявное преобразование указателя Objective C в '__unsafe_unretained id *' запрещено с ARC

[WARN] Несовместимые типы указателей, отправляющие "__string id" параметру типа "__unsafe_unretained id *"

Объявление -getObjects:range: выглядит так:

- (void)getObjects:(id [])aBuffer range:(NSRange)aRange

Таким образом, из полученного сообщения об ошибке я предполагаю, что должен передать "__unsafe_unretained id *" в "getObjects:(id [])aBuffer". Итак, чтобы исправить это, я объявляю свой идентификатор как __unsafe_unretained следующим образом:

__unsafe_unretained id argv = (__bridge __unsafe_unretained id)(calloc(args.count + 1, sizeof(id)));

И обновите эту строку следующим образом:

[args getObjects:&argv range:NSMakeRange(0, args.count)];

Теперь у меня нет никаких ошибок, но при вызове DADiskMountWithArguments я получаю следующую ошибку:

Преобразование указателя Objective C в 'CFStringRef *' (он же const struct __CFString **) запрещено с ARC

Так что здесь я застрял, так как не смог исправить эту ошибку, и я не знаю, допустил ли я ошибки раньше или не нашел верного пути, отправьте CFStringRef, поэтому я решил обратиться за советом сюда.

Вот как это выглядит в контексте, где args - это NSArray, объявленный ранее:

__unsafe_unretained id argv = (__bridge __unsafe_unretained id)(calloc(args.count + 1, sizeof(id)));

[args getObjects:&argv range:NSMakeRange(0, args.count)];

DADiskMountWithArguments((DADiskRef) disk, (__bridge CFURLRef) url, kDADiskMountOptionDefault, NULL, (__bridge void *)self, (CFStringRef *)argv );

Так что мой вопрос: как сделать этот метод дружественным ARC, или есть другой / лучший способ получить NSArray к CFStringRef с NULL-завершением *

1 ответ

Решение

Попробуй это:

CFStringRef *argv = calloc(args.count + 1, sizeof(CFStringRef));
CFArrayGetValues((__bridge CFArrayRef)args, CFRangeMake(0, args.count), (const void **)argv );
DADiskMountWithArguments((DADiskRef) disk, (CFURLRef) url, kDADiskMountOptionDefault,
                     DiskMountCallback, self, argv);
free(argv);

Проблемы с управлением памятью Core Foundation/Cocoa отсутствуют, поскольку CFArrayGetValues() не дает вам права собственности на возвращаемые значения.

Другие вопросы по тегам