Преобразование 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

[ПРЕДУПРЕЖДЕНИЕ] Несовместимые типы указателей, отправляющие '__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 с нулевым завершением *


person Erik Berglund    schedule 27.03.2015    source источник
comment
Что вы имеете в виду, что это не разрешено в ARC? Что не разрешено? Какая точная строка и ошибка?   -  person Aaron Brager    schedule 28.03.2015
comment
Да, извините за неясность. Я обновил свой вопрос с проблемными строками.   -  person Erik Berglund    schedule 28.03.2015


Ответы (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() не дает вам права собственности на возвращаемые значения.

person Ken Thomases    schedule 28.03.2015
comment
Спасибо, это прекрасно работает. Я изучу ваши изменения, чтобы лучше понять это. - person Erik Berglund; 28.03.2015
comment
Пожалуйста. NSArray подключен к своему аналогу Core Foundation CFArray по бесплатному номеру. Типы Core Foundation не управляются ARC. Переключившись на Core Foundation API, вы обходите проблемы с ARC. Есть только одно приведение __bridge для передачи NSArray в CFArrayGetValues(), и это не связано с какими-либо сложными проблемами управления памятью. - person Ken Thomases; 28.03.2015