Objective-C Block修改间接作用域变量,是否误解了Block捕获机制?
问题分析:Objective-C Block与C++混合编程中的变量捕获问题
以下是复现问题的最简代码:
#import <Foundation/Foundation.h> @interface ObjCClass:NSObject @property void (^aBlockInner) (); -(void)method; -initWithBlock:(void (^)())aBlock; @end @implementation ObjCClass - (void)method{ self->_aBlockInner(); } -(instancetype)initWithBlock:(void (^)())aBlock { self->_aBlockInner = aBlock; return self; } @end struct cppClass{ cppClass(){ objCClassInstance = [[ObjCClass alloc] initWithBlock:^{ modifyY(); }]; [objCClassInstance method]; } void modifyY() { y++; } int y = 0; ObjCClass* objCClassInstance; }; int main() { cppClass a{}; NSLog(@"Y is:%d",a.y); }
编译命令:clang++ main.mm -framework Foundation
成员变量y原本预期保持不变,因为按照理解Block会复制它“捕获”的变量,但最终输出结果为:
Y is:1
我是否误解了Objective-C Block的机制?
问题原因
你并没有误解Objective-C Block的核心机制,问题出在C++成员函数的隐式this指针捕获上:
- 当你在Block中调用
modifyY()时,这个函数是cppClass的非静态成员函数,C++编译器会自动为该函数传入当前对象的this指针,Block实际捕获的是这个this指针,而非成员变量y本身。 - 当Block执行
modifyY()时,通过this指针直接操作了原cppClass对象的成员变量y,自然会导致y的值从0变为1。
验证与修正
如果想要让Block捕获y的副本而非this指针,可以显式将y赋值给局部变量后再捕获:
cppClass(){ int localY = y; // 显式创建局部变量 objCClassInstance = [[ObjCClass alloc] initWithBlock:^{ localY++; // 修改的是副本,不影响原成员变量 }]; [objCClassInstance method]; }
此时运行程序,输出会是Y is:0,符合你最初的预期。
需要注意的是,在Objective-C与C混合编程场景下,Block对C类成员的捕获逻辑会偏向C++的规则——优先捕获this指针以保证成员函数能正常访问类成员,而非默认捕获单个成员变量的副本。
内容的提问来源于stack exchange,提问作者Spyros Mourelatos
相关产品推荐
相关产品推荐

