__block NSString转NSString及std::string时遇崩溃问题求助
首先,咱们先拆解你遇到的两个核心问题:为什么会抛出-[__NSMallocBlock__ UTF8String]: unrecognized selector错误,以及如何正确实现异步操作到std::string的转换。
错误根源:异步时序 + 内存混乱
你的代码里有一个致命的设计矛盾:[Something somecall]是异步调用——它会立刻返回,而传入的completion block要等到异步任务完成后才会执行。但你却试图在somefunc里同步返回结果,这就导致:
当return std::string([vals UTF8String]);执行时,completion block根本还没跑,vals要么还是初始的nil,要么因为ARC的内存管理,栈上的__block变量已经被回收,内存空间被其他对象(比如某个block实例)占用,这才出现了“给block发NSString消息”的崩溃。
那个__NSMallocBlock__的错误提示,本质上是野指针访问导致的类型混乱,而不是__block修饰符本身的问题——你用__block是为了在block内修改变量,这个用法是对的,但架不住异步时序的问题拖后腿。
最优解决方案:改用异步回调(推荐)
既然底层是异步操作,硬要同步返回结果只会带来线程阻塞、内存问题甚至死锁。最合理的做法是把somefunc改成异步接口,用completion block传递最终的std::string结果。
代码实现
+ (void)somefuncWithCompletion:(void(^)(std::string))completion { [[Something somecall] completion:^(id someParams) { NSString *vals = @"yay"; // 安全转换:先判断NSString是否有效,再转成std::string std::string result = vals ? std::string([vals UTF8String]) : std::string(); if (completion) { completion(result); } }]; }
调用方式
[YourClassName somefuncWithCompletion:^(std::string resultStr) { // 在这里处理转换后的std::string NSLog(@"拿到结果:%s", resultStr.c_str()); }];
备选方案:同步等待(仅非主线程可用)
如果你因为特殊需求必须同步返回结果,可以用信号量(dispatch_semaphore_t)强制等待异步任务完成,但绝对不能在主线程调用——会导致UI卡死甚至死锁。
代码实现
+ (std::string)somefunc { dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); __block NSString *vals = nil; [[Something somecall] completion:^(id someParams) { vals = @"yay"; // 异步任务完成,发送信号 dispatch_semaphore_signal(semaphore); }]; // 等待信号,设置超时时间避免永久阻塞(这里设10秒) dispatch_semaphore_wait(semaphore, dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC)); // ARC下不需要手动释放信号量,MRC需要加dispatch_release(semaphore); // 安全转换:处理vals为nil的情况 return vals ? std::string([vals UTF8String]) : std::string(); }
总结
- 优先选择异步回调方案,这是iOS异步编程的最佳实践,从根源上避免了时序和内存问题。
- 同步等待方案只适合后台线程的特殊场景,用的时候一定要加超时保护,防止线程永久阻塞。
内容的提问来源于stack exchange,提问作者Yang Lu

