我正面临一个奇怪的崩溃,NSNumber
的一个实例似乎已被释放,尽管它仍然存在于数组中。我已经创建了一个系统来从远程服务器下载多个文件,并有一个块来指示进度(真正的平均进度)。而进度的计算会导致崩溃。崩溃并不一致,而且经常发生#34; at可以在任何时候发生。 [_NSProgressFractionTuple floatValue]: unrecognized selector sent to instance 0x17042ab80
让我相信NSNumber
已被解除分配,我无法看到这是如何可能的。
提供完整的方法代码:
- (void)downloadFilesFromURLs:(NSArray<NSString *> *)urlPaths withProgress:(void (^)(float progress))progressBlock completion:(void (^)(NSError *error))completionBlock {
NSMutableArray *toLoad = [[NSMutableArray alloc] init];
for(NSString *path in urlPaths) {
if([self fileForURL:path] == nil) {
[toLoad addObject:path];
}
}
NSInteger itemsToLoad = toLoad.count;
if(itemsToLoad <= 0) {
if(completionBlock) {
completionBlock(nil);
}
return;
}
// Set progresses to zero
__block NSMutableArray *progresses = [[NSMutableArray alloc] init];
for(int i=0; i<itemsToLoad; i++) [progresses addObject:[[NSNumber alloc] initWithFloat:.0f]];
__block NSInteger requestsOut = itemsToLoad;
__block NSError *latestError = nil;
for(int i=0; i<itemsToLoad; i++) {
NSInteger index = i;
[self downloadFileFromURL:toLoad[index] named:nil withProgress:^(float progress) {
progresses[index] = [[NSNumber alloc] initWithFloat:progress];
if(progressBlock) {
float overallProgress = .0f;
for(NSNumber *number in [progresses copy]) {
overallProgress += number.floatValue;
}
progressBlock(overallProgress/itemsToLoad);
}
} completion:^(NSString *filePath, NSError *error) {
if(error) latestError = error;
requestsOut -= 1;
if(requestsOut <= 0) {
if(completionBlock) {
completionBlock(latestError);
}
}
}];
}
}
代码说明:
因此,此方法接受一组URL。然后检查是否已下载某些文件并创建一个仅包含需要下载的URL的新阵列。如果所有文件都存在或没有提供URL,则调用完成并且操作中断。
接下来,我创建一个可变数组并用NSNumber
个实例填充它,所有实例都具有零值。我记得会有多少请求,我会为错误创建一个占位符。我遍历所有的URL并初始化请求,每个URL都会报告进度和完成情况,并且这两个都在主线程上。
因此,在进程块中,我访问进度数组以通过索引分配新值。然后,我计算平均进度并将整体进度报告给输入块。
请求完成减少了请求计数器的数量,当该请求计数器降至零时,将调用输入完成。
情况:
这一切都按预期工作,整个过程是正确的。给定的值都是有效的,所有文件都在服务器上并且可以访问。当应用程序没有崩溃时,一切正常。
但是当它崩溃时它崩溃了
for(NSNumber *number in [progresses copy]) {
overallProgress += number.floatValue;
}
并且崩溃是随机的,但无论如何number.floatValue
似乎正在访问它不应该的内存。
我现在有一个解决方案,我用纯C指针progresses
替换了float *progresses = malloc(sizeof(float)*itemsToLoad);
数组,该指针在完成时被释放。它似乎工作但仍然,我在这里失踪了什么? NSNumbers
无法在这里工作的数组可能是什么原因?
其他一些信息:
@(progress)
语法,但是为了解决问题而将其更改为显式分配progresses
不需要__block
,我添加它以防万一谢谢!
答案 0 :(得分:1)
NSMutableArray
不是线程安全的。因此,即使没有明确的内存管理问题,如果同时通过两个不同的线程访问NSMutableArray
,也可能发生坏事。我相信在串行队列中调度withProgress
块可以解决问题。