ary*_*axt 50 multithreading objective-c nsmutablearray ios
我一直试图解决这个崩溃将近一个星期.应用程序崩溃,没有任何异常或堆栈跟踪.在僵尸模式下运行仪器时,应用程序不会以任何方式崩溃.
我有一个在不同的线程上调用的方法.修复崩溃的解决方案正在取代
[self.mutableArray removeAllObjects];
Run Code Online (Sandbox Code Playgroud)
同
dispatch_async(dispatch_get_main_queue(), ^{
[self.searchResult removeAllObjects];
});
Run Code Online (Sandbox Code Playgroud)
我认为这可能是一个时间问题,所以我尝试同步它,但它仍然崩溃:
@synchronized(self)
{
[self.searchResult removeAllObjects];
}
Run Code Online (Sandbox Code Playgroud)
这是代码
- (void)populateItems
{
// Cancel if already exists
[self.searchThread cancel];
self.searchThread = [[NSThread alloc] initWithTarget:self
selector:@selector(populateItemsinBackground)
object:nil];
[self.searchThread start];
}
- (void)populateItemsinBackground
{
@autoreleasepool
{
if ([[NSThread currentThread] isCancelled])
[NSThread exit];
[self.mutableArray removeAllObjects];
// Populate data here into mutable array
for (loop here)
{
if ([[NSThread currentThread] isCancelled])
[NSThread exit];
// Add items to mutableArray
}
}
}
Run Code Online (Sandbox Code Playgroud)
NSMutableArray的这个问题不是线程安全的吗?
Dan*_*iel 87
没有.
它不是线程安全的,如果你需要从另一个线程修改你的可变数组,你应该使用它NSLock来确保一切按计划进行:
NSLock *arrayLock = [[NSLock alloc] init];
[...]
[arrayLock lock]; // NSMutableArray isn't thread-safe
[myMutableArray addObject:@"something"];
[myMutableArray removeObjectAtIndex:5];
[arrayLock unlock];
Run Code Online (Sandbox Code Playgroud)
Jin*_*han 36
正如其他人已经说过的那样,NSMutableArray不是线程安全的.如果有人想要在线程安全的环境中实现多于removeAllObject,除了使用锁定之外,我将使用GCD提供另一种解决方案.您需要做的是同步读取/更新(替换/删除)操作.
首先获取全局并发队列:
dispatch_queue_t concurrent_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
Run Code Online (Sandbox Code Playgroud)
如需阅读:
- (id)objectAtIndex:(NSUInteger)index {
__block id obj;
dispatch_sync(self.concurrent_queue, ^{
obj = [self.searchResult objectAtIndex:index];
});
return obj;
}
Run Code Online (Sandbox Code Playgroud)
对于插入:
- (void)insertObject:(id)obj atIndex:(NSUInteger)index {
dispatch_barrier_async(self.concurrent_queue, ^{
[self.searchResult insertObject:obj atIndex:index];
});
}
Run Code Online (Sandbox Code Playgroud)
来自Apple Doc的dispatch_barrier_async:
当障碍块到达专用并发队列的前面时,它不会立即执行.相反,队列等待,直到其当前正在执行的块完成执行.此时,屏障块自行执行.在屏障块完成之后,在屏障块之后提交的任何块都不会执行.
类似于删除:
- (void)removeObjectAtIndex:(NSUInteger)index {
dispatch_barrier_async(self.concurrent_queue, ^{
[self.searchResult removeObjectAtIndex:index];
});
}
Run Code Online (Sandbox Code Playgroud)
编辑:实际上我今天找到了另一种更简单的方法,通过使用GCD提供的串行队列来同步对资源的访问.
从Apple Doc 并发编程指南>调度队列:
当您希望任务按特定顺序执行时,串行队列非常有用.串行队列一次只执行一个任务,并始终从队列的头部提取任务.您可以使用串行队列而不是锁来保护共享资源或可变数据结构.与锁不同,串行队列确保以可预测的顺序执行任务.只要您将任务异步提交到串行队列,队列就永远不会死锁.
创建串行队列:
dispatch_queue_t myQueue = dispatch_queue_create("com.example.MyQueue", NULL);
Run Code Online (Sandbox Code Playgroud)
将任务异步调度到串行队列:
dispatch_async(myQueue, ^{
obj = [self.searchResult objectAtIndex:index];
});
dispatch_async(myQueue, ^{
[self.searchResult removeObjectAtIndex:index];
});
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你!
Nat*_*Day 19
除了也NSLock可以使用@synchronized(condition-object)之外,如果你只想修改同一个数组实例的内容,你必须确保数组的每次访问都包含在一个@synchronized同一个对象中作为条件对象.然后你可以使用数组本身作为条件对象,否则你将不得不使用你知道不会消失的其他东西,父对象,即自我,是一个很好的选择,因为它总是相同的相同的数组.
@property属性中的原子只会使数组线程安全而不修改内容,即self.mutableArray= ...是线程安全但[self.mutableArray removeObject:]不是.
sas*_*ash 12
__weak typeof(self)weakSelf = self;
@synchronized (weakSelf.mutableArray) {
[weakSelf.mutableArray removeAllObjects];
}
Run Code Online (Sandbox Code Playgroud)
这篇惊人的文章将解释这一切:
http://refactr.com/blog/2012/10/ios-tips-synchronized/
由于提到了串行队列:使用可变数组,只是询问"它是否是线程安全的"是不够的.例如,确保removeAllObjects不会崩溃是好的,但是如果另一个线程同时尝试处理数组,它将在删除所有元素之前或之后处理数组,并且你真的必须想想应该是什么行为.
创建一个负责此数组的类+对象,为其创建一个串行队列,并通过该串行队列上的类执行所有操作,这是最简单的方法,可以通过同步问题让您的大脑受到伤害.