iOS编译报错:无法在block内引用可变修改类型的声明
解决你的C数组+Block报错问题
嘿,我一眼就看到你代码里的问题了——你用了CGPoint pointArray[lines.count];这种变长C数组(VLA),这玩意儿在Objective-C里可是个“定时炸弹”,大概率就是触发报错的元凶。
为啥这么说?
- 标准C里,数组长度得是编译期常量,虽然苹果的编译器勉强支持运行时指定长度的VLA,但栈空间本来就很小(一般也就几MB),如果
lines.count稍微大一点,直接就栈溢出崩溃了。 - 就算count很小,栈上的变量在block里也有潜在的生命周期风险(哪怕你现在用的是同步遍历,万一后续改成异步执行,直接就野指针了)。
给你几个靠谱的解决方案,按需选:
方案1:用NSMutableArray存(最符合OC风格,省心)
OC的集合类天生就是用来处理动态大小的,内存堆上分配,ARC自动管理,完全没栈溢出的顾虑。假设你的lines里存的是包装了CGPoint的NSValue(毕竟OC集合不能直接存基本类型),代码改成这样:
NSMutableArray *pointArray = [NSMutableArray arrayWithCapacity:lines.count]; [lines enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { // 把NSValue转成CGPoint CGPoint currentPoint = [obj CGPointValue]; // 存进数组 [pointArray addObject:[NSValue valueWithCGPoint:currentPoint]]; // 直接打印或者使用 NSLog(@"%f", currentPoint.y); }];
后续要取数组里的点,再用CGPointValue转回来就行,全程不用操心内存。
方案2:堆上分配C数组(追求性能时用)
如果你特别在意C数组的访问效率,那就在堆上用malloc分配内存,这样不受栈大小限制,只是要记得手动释放:
// 分配内存,计算好每个CGPoint的大小乘以数量 CGPoint *pointArray = malloc(sizeof(CGPoint) * lines.count); // 一定要检查分配是否成功,避免空指针 if (!pointArray) { NSLog(@"内存分配失败"); return; } [lines enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { CGPoint currentPoint = [obj CGPointValue]; pointArray[idx] = currentPoint; NSLog(@"%f", pointArray[idx].y); }]; // 用完必须释放,ARC管不了malloc的内存! free(pointArray);
这种方式保留了C数组的高效,又解决了栈溢出问题,就是得记得手动free,不然会内存泄漏。
方案3:直接在block里处理(最简洁,不需要存数组的话用)
如果你只是想遍历的时候打印每个点的y值,根本没必要创建数组啊!直接在block里处理就行:
[lines enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { CGPoint currentPoint = [obj CGPointValue]; NSLog(@"%f", currentPoint.y); }];
省掉数组的创建,代码更清爽,也完全避开了数组相关的所有问题。
总结
- 只是遍历处理选方案3,最省事;
- 需要存储所有点选方案1,OC风格,内存不用管;
- 追求极致性能且必须用C数组,再选方案2,记得手动释放内存。
内容的提问来源于stack exchange,提问作者lovejuly
相关产品推荐
相关产品推荐

