访问块内的C数组(可变长度数组)Objective-C

20

块是可以的,但怎么写C数组呢?

考虑下面这种简化情况:

CGPoint points[10];
[myArray forEachElementWithBlock:^(int idx) {
    points[idx] = CGPointMake(10, 20); // error here
    // Cannot refer to declaration with an array type inside block
}];

在寻找一段时间后,我找到了这个可能的解决方案,将其放入结构体中:

__block struct {
    CGPoint points[100];
} pointStruct;

[myArray forEachElementWithBlock:^(int idx) {
    pointStruct.points[idx] = CGPointMake(10, 20);
}];

这个方法可以行得通,但是我必须动态创建c数组,有一些限制:

int count = [str countOccurencesOfString:@";"];
__block struct {
    CGPoint points[count]; // error here
    // Fields must have a constant size: 'variable length array in structure' extension will never be supported
} pointStruct;

我如何在一个block中访问我的CGPoint数组?

或者说,这是否完全可能,还是必须重写block方法才能获得所有功能?

2个回答

21

对我而言,另一个简单的可行解决方案是以下内容:

CGPoint points[10], *pointsPtr;
pointsPtr = points;
[myArray forEachElementWithBlock:^(int idx) {
    pointsPtr[idx] = CGPointMake(10, 20);
}];

1
我对“,*pointsPtr”和关联不熟悉。它创建了一个指针,但是在最后我需要释放什么吗? - user207616
2
您不必释放任何东西。指针pointsPtr是一个普通变量,其值是(在pointsPtr = points之后)数组points的第一个元素的内存地址。因此,当您声明points[10]时,编译器会在堆栈上为10个CGPoint保留内存,然后pointsPtr只是指向这个内存。由于您没有使用malloc/calloc在堆上分配任何内存给pointsPtr,因此无需释放任何内容。这就是我喜欢这种方法的原因。顺便说一下,我也可以用CGPoints points[10]; CGPoint *pointsPtr = points;开始我的代码,这完全相同。 - cefstat
9
在这种情况下,块只在此范围内使用是正确的。然而,一般情况下,块可以被复制并从函数中返回,在那些变量不存在时被后续使用。在这种情况下,这个解决方案就不再适用,并且可能会覆盖任意内存。 - user102008
这是不安全的,但如果你100%确定你不会在函数/方法范围之外到达此块,则可以使用它。一般来说,这种黑客行为会给你带来大量的技术义务,因此它们必须至少有良好的注释。 - Netherwire

14

也许你可以在堆上分配该数组?

// Allocates a plain C array on the heap. The array will have
// [myArray count] items, each sized to fit a CGPoint.
CGPoint *points = calloc([myArray count], sizeof(CGPoint));
// Make sure the allocation succeded, you might want to insert
// some more graceful error handling here.
NSParameterAssert(points != NULL);

// Loop over myArray, doing whatever you want
[myArray forEachElementWithBlock:^(int idx) {
    points[idx] = …;
}];

// Free the memory taken by the C array. Of course you might
// want to do something else with the array, otherwise this
// excercise does not make much sense :)
free(points), points = NULL;

你可以在这之后使用 dispatch_sync 调用 someQueue 来删除数组吗? - James Bedford
我认为我不必使用GCD,因为它是一个线性同步操作,所以我可以在我的块调用之后简单地删除它,对吗?您能否解释一下free()的作用,并告诉我如何删除数组? - user207616
抱歉,dispatch_async 只是一个例子,显然不是最好的。我会重写答案,使其更接近您实际的代码。 - zoul
1
考虑到在代码块中的代码执行时,points是否已被释放,这个是如何工作的?当你声明代码块时,GCD是否会复制points? - James Bedford
1
在这种情况下,块仅在此范围内使用是正确的。然而,一般来说,块可以被复制并从函数中返回,并在这些变量不再存在时稍后使用。在那种情况下,这个解决方案将无法工作并且会覆盖任意内存。 - user102008
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接