我正在使用Objective-C中的块,试图找到一个可重用的机制,它将获取任意代码块和一个锁对象,然后在新线程上执行代码块,同步提供锁定。我们的想法是提出一种简单的方法来移动主线程的所有同步开销/等待,以便应用程序的UI始终响应。
我提出的代码非常简单,就像:
- (void) executeBlock: (void (^)(void))block {
block();
}
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
@synchronized(lock) {
block();
}
};
[self performSelectorInBackground:@selector(executeBlock:) withObject:syncBlock];
}
例如,您可能有一些类似的方法:
- (void) addObjectToSharedArray:(id) theObj {
@synchronized(array) {
[array addObject: theObj];
}
}
- (void) removeObjectFromSharedArray:(id) theObj {
@synchronized(array) {
[array removeObject: theObj];
}
}
哪个工作正常,但在等待锁定时阻塞调用线程。这些可以改写为:
- (void) addObjectToSharedArray:(id) theObj {
[self runAsyncBlock:^{
[array addObject: theObj];
} withLock: array];
}
- (void) removeObjectFromSharedArray:(id) theObj {
[self runAsyncBlock: ^{
[array removeObject: theObj];
} withLock:array];
}
应始终立即返回,因为只有后台线程才能在锁定中竞争。
问题是,此代码在executeBlock:
之后崩溃而没有产生任何输出,错误消息,崩溃日志或任何其他有用的东西。我的方法中存在根本缺陷吗?如果没有,有关为什么会崩溃的任何建议?
编辑:
有趣的是,如果我只是这样做,它就可以正常运行:
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
void(^syncBlock)() = ^{
@synchronized(lock) {
block();
}
};
syncBlock();
}
但当然这会阻止调用线程,这在很大程度上违背了目的。块是否可能不跨越线程边界?我不这么认为,因为那样会在很大程度上打败首先拥有它们的目的。
答案 0 :(得分:4)
记得调用[block copy]
否则它没有被正确保留,因为块在堆栈上创建并在退出范围时被销毁,除非你调用copy
它不会移动到堆甚至retain
是调用。
- (void) runAsyncBlock: (void (^)(void))block withLock:(id)lock {
block = [[block copy] autorelease];
void(^syncBlock)() = ^{
@synchronized(lock) {
block();
}
};
syncBlock = [[syncBlock copy] autorelease];
[self performSelectorInBackground:@selector(executeBlock:) withObject:syncBlock];
}