我完全被这个问题难住了,希望有人能帮助我:
A :
- (void)setBlock:(BOOL(^)(id sender))block {
myBlock = Block_copy(block);
}
- (BOOL)runBlock:(id)sender {
myBlock(sender);
}
B类:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotificationx {
//The outer block provides behaviour according to strategy pattern:
[classAInstance setBlock:^BOOL(id sender) {
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
//The inner block is a special case of behaviour where I want the task to run asynchronously:
[queue addOperationWithBlock:^(void) {
NSLog(@"sender: %@", [sender class]);
[sender doSomething];
}];
return YES;
}];
}
然后当GUI事件导致classinstance调用- (BOOL)runBlock;
时(它应该是)我得到以下崩溃堆栈:
0 objc_exception_throw
3 __forwarding_prep_0___
4 __58-[ClassB applicationDidFinishLaunching:]_block_invoke_037
5 -[NSBlockOperation main]
11 start_wqthread
我得到的最后一个调试日志是:
sender: __NSMallocBlock__
-[__NSMallocBlock__ doSomething]: unrecognized selector sent to instance 0x10043f2a0
为什么block的参数突然变成了__NSMallocBlock__
呢?我显然是传递其他东西(即sender
)给它,不是吗?
看起来当你调用runBlock时,你正在传递一个块作为发送者。我可以很好地运行你的代码。Matt Gallagher有一篇关于如何实现块的文章,可以帮助您调试问题。
如果你复制一个NSStackBlock,它会返回一个nssmalllocblock(表示已更改的分配位置)。
找到原因了。啊,我现在觉得自己很蠢。
错误是将块(以及第二个块)作为关联对象通过:
static NSString * const FirstBlockKey;
static NSString * const SecondBlockKey;
objc_setAssociatedObject(self, FirstBlockKey, blockA, OBJC_ASSOCIATION_COPY);
objc_setAssociatedObject(self, SecondBlockKey, blockB, OBJC_ASSOCIATION_COPY);
虽然我应该清楚地使用这个:
objc_setAssociatedObject(self, (void *)&FirstBlockKey, block, OBJC_ASSOCIATION_COPY);
FirstBlockKey
和SecondBlockKey
本身明显都是0x0
,而它们自己的指针却不是。
这样它就调用了错误的块(因为它们都被分配到相同的' 0x0'键)。块具有不同的返回和参数类型,这似乎导致了传递块参数的奇怪交换。
,说:乔, 瑞安,wbyoung,谢谢大家的努力!
Joe的回答看起来很有可能是对的。为了让别人知道实际发生了什么,您还必须共享调用runBlock的代码,但是给定您提供的方法的名称,它可能看起来像:
[classAInstance runBlock:^BOOL(id sender) {
// some code
}];
实际上会打印NSStackBlock
(当然,除非先复制块,在这种情况下,它将是NSMallocBlock
)。
[classAInstance runBlock:@"Hello world"];
将导致输出:
sender: NSString
-[NSString doSomething]: unrecognized selector sent to instance
没有你的runBlock调用,虽然没有办法知道哪里出了问题。也有可能你用正确的参数调用方法,但是你有一个内存分配问题,导致一个块被分配在你期望另一个对象存在的区域,但这可能不太可能。
这可能是你的问题:
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
你正在创建一个NSOperationQueue,然后自动释放它,然后期望它为你工作。如果您希望在单独的线程中异步执行工作,请使用dispatch_async()和并发队列:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^() {
NSLog(@"sender: %@", [sender class]);
[sender doSomething];
});