ARC не нравится преобразование в void *
, что функции Block_ * ожидают в качестве аргументов, поскольку ARC не может рассуждать о владении типами, не сохраняемыми.Вам необходимо использовать приведения мостов, чтобы сообщить ARC, как он должен управлять владением объектами, которые вовлечены, или что он вообще не должен управлять их владением.
Вы можете решить проблемы ARC, используя код ниже:
- (void)beginSheet:(NSWindow *)sheet
modalForWindow:(NSWindow *)docWindow
didEndBlock:(void (^)(NSInteger returnCode))block
{
[self beginSheet:sheet
modalForWindow:docWindow
modalDelegate:self
didEndSelector:@selector(my_blockSheetDidEnd:returnCode:contextInfo:)
contextInfo:Block_copy((__bridge void *)block)];
}
- (void)my_blockSheetDidEnd:(NSWindow *)sheet
returnCode:(NSInteger)returnCode
contextInfo:(void *)contextInfo
{
void (^block)(NSInteger) = (__bridge_transfer id)contextInfo;
block(returnCode);
}
В первом методе
Block_copy((__bridge void *)block)
означает следующее: приведение block
к void *
с использованием преобразования __bridge
.Этот акт сообщает ARC, что он не должен управлять владением операндом, поэтому ARC не будет касаться block
в отношении управления памятью.С другой стороны, Block_copy()
действительно копирует блок, поэтому вам необходимо сбалансировать эту копию с выпуском позже.
Во втором методе
void (^block)(NSInteger) = (__bridge_transfer id)contextInfo;
означает следующее: castcontextInfo
до id
(универсальный тип объекта в Objective-C) с приведением __bridge_transfer
.Этот акт говорит ARC, что он должен выпустить contextInfo
.Поскольку переменная block
имеет значение __strong (квалификатор по умолчанию), блок сохраняется, и в конце метода он наконец освобождается.Конечным результатом является то, что block
освобождается в конце метода, что является ожидаемым поведением.
В качестве альтернативы, вы можете скомпилировать эту категорию с помощью -fno-objc-arc
.Xcode позволяет создавать файлы в одном проекте с поддержкой ARC или без нее.