Ios NSBlockOperation EXC\u坏访问
我创建了一个实现了几个方法的类。这些方法由另一个类调用,并通过NSBlockOperation进行管理 我的NSBlockOperation工作正常,我在尝试计算变量时遇到问题: EXC\u坏访问 我在互联网上做了很多研究,是最接近我问题的人。我试着像sugerito那样做,但你遇到了同样的问题 你有什么建议吗 编辑: 这是堆栈跟踪:Ios NSBlockOperation EXC\u坏访问,ios,objective-c,objective-c++,Ios,Objective C,Objective C++,我创建了一个实现了几个方法的类。这些方法由另一个类调用,并通过NSBlockOperation进行管理 我的NSBlockOperation工作正常,我在尝试计算变量时遇到问题: EXC\u坏访问 我在互联网上做了很多研究,是最接近我问题的人。我试着像sugerito那样做,但你遇到了同样的问题 你有什么建议吗 编辑: 这是堆栈跟踪: 2015-05-09 15:24:45.976 OutParameters[12326:743087] Stack trace : ( 0 OutPa
2015-05-09 15:24:45.976 OutParameters[12326:743087] Stack trace : (
0 OutParameters 0x000000010e5d6602 -[ListOperation _method1:] + 194
1 OutParameters 0x000000010e5d646f __25-[ListOperation method1:]_block_invoke + 95
2 Foundation 0x000000010e74257f __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
3 Foundation 0x000000010e6830b2 -[NSBlockOperation main] + 98
4 Foundation 0x000000010e665774 -[__NSOperationInternal _start:] + 645
5 Foundation 0x000000010e665383 __NSOQSchedule_f + 184
6 libdispatch.dylib 0x00000001113f4614 _dispatch_client_callout + 8
7 libdispatch.dylib 0x00000001113db6a7 _dispatch_queue_drain + 2176
8 libdispatch.dylib 0x00000001113dacc0 _dispatch_queue_invoke + 235
9 libdispatch.dylib 0x00000001113de3b9 _dispatch_root_queue_drain + 1359
10 libdispatch.dylib 0x00000001113dfb17 _dispatch_worker_thread3 + 111
11 libsystem_pthread.dylib 0x0000000111761637 _pthread_wqthread + 729
12 libsystem_pthread.dylib 0x000000011175f40d start_wqthread + 13
)
修改后的代码:
- (IBAction)testCallMethod:(id)sender {
NSString * output;
[self.listOperationObj method1:&output];
NSLog(@"Output: %@", output);
}
及
如果我反复按下按钮,此更改会产生相同的错误。直接的问题与块无关。您有一个代码片段,上面写着:
- (IBAction)testCallMethod:(id)sender {
NSString *__autoreleasing * output;
[self.listOperationObj method1:output];
NSLog(@"Output: %@", *output);
}
这不起作用,因为
output
不会指向有效的内存地址,当您尝试使用*output=…
取消对未初始化指针的引用时,它将崩溃
相反,
这应该是:
- (IBAction)testCallMethod:(id)sender {
NSString *output;
[self.listOperationObj method1:&output];
NSLog(@"Output: %@", output);
}
现在,output
引用一个真正的NSString*
指针,您可以用对象引用填充该指针
还有第二个更深层次的问题,即对操作中实例化的对象使用
*\uu autoreleasing*
引用。操作有自己的自动释放池,因此您在testCallMethod
中使用对象时会释放对象,从而产生竞争条件
相反,通常使用完成块将数据传递回调用方。因此:
- (IBAction)testCallMethod:(id)sender {
[self.listOperationObj method2:^(NSString *output) {
NSLog(@"Output: %@", output);
}];
}
及
注意,顺便说一下,这也解决了您的示例中的另一个问题,即您必须在其中放入一个
waitUntilFinished
调用。永远不要从主线程调用waitUntilFinished
。如果像上面那样使用完成块,就不再需要了。发布崩溃时的堆栈跟踪。我已经编辑过了,谢谢。谢谢回答。我试着按照我的建议去做。这似乎只是偶尔奏效。如果我快速按下按钮,会出现同样的错误,有时甚至是第一次按下。是的,这是第二个完全无关的问题。请注意,当您尝试在视图控制器中使用输出时,它会崩溃,而不是在\u method1
中使用它。请参阅修订后的答案,以了解关于另一个问题的讨论以及如何安全地传递数据的常见解决方案。“这不起作用,因为输出将为NULL”。实际上,它应该是未初始化的。这是一个普通的C指针类型,不是弧管理类型。@newacct-同意。观察结果是,它没有指向有效的NSString*
,因此尝试取消对它的引用将失败。但我已经澄清了我的答案。谢谢
- (IBAction)testCallMethod:(id)sender {
[self.listOperationObj method2:^(NSString *output) {
NSLog(@"Output: %@", output);
}];
}
- (void)method2:(void (^)(NSString *))completionHandler {
LOGFSTART
if([self _isQueueFull] == FALSE) {
WEAK
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
STRONG
[strongSelf _method2:completionHandler];
}];
[self.queue addOperation:operation];
// [operation waitUntilFinished]; // not needed any more
}
else {
LOGE(@"TokenMgr's queue is full, aborting operation");
}
LOGFEND
}
-(void)_method2:(void (^)(NSString *))completionHandler {
std::string testString = "try put string";
NSString *output = [NSString stringWithUTF8String:testString.c_str()];
completionHandler(output);
}