Mike Ash 创建了一个使用 blocks to handle callbacks 的示例从床单上看,这看起来很不错。在 beginSheet: block alternative? 的另一个 SO 问题中,这又被用户 Enchilada 更新为与垃圾收集一起工作。 ,见下文。
@implementation NSApplication (SheetAdditions)
- (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(block)];
}
- (void)my_blockSheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
void (^block)(NSInteger returnCode) = contextInfo;
block(returnCode);
Block_release(block);
}
@end
启用 GC 时,这不适用于自动引用计数 (ARC)。作为 ARC 和 blocks 的初学者,我自己无法让它工作。我应该如何修改代码以使其与 ARC 一起工作?
我知道 Block_release() 的东西需要去掉,但我无法克服关于将 'void *' 转换为 'void (^)(NSInteger)' 被 ARC 禁止的编译错误。
最佳答案
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)
表示以下内容:使用 __bridge
转换将 block
转换为 void *
。这个转换告诉 ARC 它不应该管理操作数的所有权,因此 ARC 不会触及 block
内存管理方式。另一方面,Block_copy()
会复制 block ,因此您需要在该副本与稍后的发布之间取得平衡。
在第二种方法中,
void (^block)(NSInteger) = (__bridge_transfer id)contextInfo;
含义如下:使用 __bridge_transfer
转换将 contextInfo
转换为 id
(Objective-C 中的通用对象类型)。此转换告诉 ARC 它应该释放 contextInfo
。由于 block
变量是 __strong(默认限定符),因此 Block 被保留,并在方法结束时最终被释放。最终结果是 block
在方法结束时被释放,这是预期的行为。
或者,您可以使用 -fno-objc-arc
编译该类别。 Xcode 允许在启用或不启用 ARC 的情况下构建同一项目中的文件。
关于objective-c - 开始工作表 : block alternative with ARC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8360998/