我试图找出一个干净的方法来创建一个基于堆栈的C字符串(即char[]),可以通过块闭包捕获(通过const拷贝)。基本思想是这样的:
char myString[16] = {0};
// ... put something into myString.
dispatch_block_t block = ^(){
const size_t len = strlen(myString);
if (len)
NSLog(@"Not zero length");
};
但是这样做会导致编译器报错:
error: cannot refer to declaration with an array type inside block
我想到,我可以把字符数组放入一个结构体,但这看起来有点丑。有没有更好的办法?
堆栈分配的问题是,一旦离开函数,堆栈帧就会消失,但是块代码仍然存在,并且可能引用该堆栈帧中的变量。block通过分配和复制它引用的所有值到堆来处理这个问题,包括用__block声明的变量。理论上,它们应该能够复制静态大小的数组,但由于某些原因,它不受支持。请注意,很可能会有一些技术问题我不知道与数组相关。
所以我看到的最简单的解决方案是使用malloc/free:char *myString = calloc(16,1);
dispatch_block_t block = ^(){
const size_t len = strlen(myString);
if (len)
NSLog(@"Not zero length");
free(myString);
};
只要您不需要多次重用该块就可以。如果你需要重用这个块,那么把myString包装在一个NSData对象中,你可以在你的块中引用这个对象,并去掉free.
char *myString = calloc(16,1);
NSData *myStringData = [NSData dataWithBytesNoCopy:myString length:16 freeWhenDone:YES];
dispatch_block_t block = ^(){
const char *myString = myStringData.bytes;
const size_t len = strlen(myString);
if (len)
NSLog(@"Not zero length");
};
到这里已经一周了,我开始确信没有什么神奇的语法是我所遗漏的。为了将来的访问者的利益,这是迄今为止我发现的实现我在这里所要求的最好的方法:
typedef struct { char string[32]; } StackString;
StackString foo = {0};
strcpy(foo.string, "foo");
dispatch_block_t block = ^(){
StackString blockFoo = foo;
NSLog(@"Block String: %s", blockFoo.string);
};
for (int i = 0; i < 5; ++i)
{
sprintf(foo.string, "i = %d", i);
NSLog(@"Loop string: %s", foo.string);
block();
}
其输出为:
2013-03-31 11:30:52.778 TestClosure[98968:303] Loop string: i = 0
2013-03-31 11:30:52.780 TestClosure[98968:303] Block String: foo
2013-03-31 11:30:52.780 TestClosure[98968:303] Loop string: i = 1
2013-03-31 11:30:52.780 TestClosure[98968:303] Block String: foo
2013-03-31 11:30:52.780 TestClosure[98968:303] Loop string: i = 2
2013-03-31 11:30:52.781 TestClosure[98968:303] Block String: foo
2013-03-31 11:30:52.781 TestClosure[98968:303] Loop string: i = 3
2013-03-31 11:30:52.782 TestClosure[98968:303] Block String: foo
2013-03-31 11:30:52.782 TestClosure[98968:303] Loop string: i = 4
2013-03-31 11:30:52.782 TestClosure[98968:303] Block String: foo
这使我相信,在结构体中包装,固定大小的数组被const复制到块闭包中就可以了。