The*_*ter 6 objective-c nsmutablearray nsarray ios mapbox
在我填充了一个NSMutableArray对象并尝试用它做某事之后,它包含(id)0x0了一些索引.我认为NSMutableArray在Objective-C中根本不可能添加nil 所以我想知道为什么会发生这种情况.
不幸的是,"有时候".它可以通过下载超过5000个瓷砖来重现,只是为了获得足够高的金额以便发生这种情况.即使有超过5000个瓷砖,它有时也会完美无缺.
我的应用程序有一个按钮,可以开始下载特定区域的地图图块.下载在后台线程中并行发生,并为每个下载的磁贴报告.
为了允许取消下载,在我的下载器单例中,我有一个临时表NSMutableArray,可以保存每个下载的磁贴的哈希值.取消后,我可以使用该哈希列表删除数据库中的每个已保存的磁贴.
在下载过程中保存哈希似乎没问题,但是当我真的想要对它做任何事情时(我用[_currentTileHashes copy]它来改变它NSArray以给予删除方法),它会抛出NSInvalidArgumentException一行说:
-[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[3402]
Run Code Online (Sandbox Code Playgroud)
当我使用调试器检查_currentTileHashes可变数组时,我确实看到一个或两个索引实际上是nil或(id)0x0.这个截图说明了它:
此代码来自每个tile下载的回调,它会散列磁贴,将其添加到hashes数组并回调UI以获取进度:
- (void)tileCache:(RMTileCache *)tileCache didBackgroundCacheTile:(RMTile)tile withIndex:(NSUInteger)tileIndex ofTotalTileCount:(NSUInteger)totalTileCount {
DebugLog(@"Cached tile %lu of %lu.", (unsigned long)tileIndex, (unsigned long)totalTileCount);
if (_currentlyDownloading) {
float progress = (float)tileIndex / (float)totalTileCount;
NSDictionary *progressDict = @{@"progress" : [NSNumber numberWithFloat:progress],
@"routeId" : _downloadingRoute.routeId};
[_currentTileHashes addObject:[RMTileCache tileHash:tile]];
[[NSNotificationCenter defaultCenter]
postNotificationName:@"routeTileDownloaded"
object:progressDict];
}
}
Run Code Online (Sandbox Code Playgroud)
这是瓦片被散列的方式(这是来自Mapbox iOS SDK):
+ (NSNumber *)tileHash:(RMTile)tile
{
return [NSNumber numberWithUnsignedLongLong:RMTileKey(tile)];
}
uint64_t RMTileKey(RMTile tile)
{
uint64_t zoom = (uint64_t)tile.zoom & 0xFFLL; // 8bits, 256 levels
uint64_t x = (uint64_t)tile.x & 0xFFFFFFFLL; // 28 bits
uint64_t y = (uint64_t)tile.y & 0xFFFFFFFLL; // 28 bits
uint64_t key = (zoom << 56) | (x << 28) | (y << 0);
return key;
}
Run Code Online (Sandbox Code Playgroud)
最后,发生异常的代码:
- (void)tileCacheDidCancelBackgroundCache:(RMTileCache *)tileCache {
DebugLog(@"Finished canceling tile download");
[tileCache removeAllCachedImagesForTileHashes:[_currentTileHashes copy]];
[[NSNotificationCenter defaultCenter]
postNotificationName:@"routeTileDownloadCanceled"
object:nil];
}
Run Code Online (Sandbox Code Playgroud)
在iOS 8.4,8.4.1(iPhone 6)和7.1(iPhone 4)上测试
如果不清楚,请随时要求更多澄清.
NSMutableArray不是线程安全的,因此从多个并发后台下载更新实例可能会导致阵列损坏 - 正如您所看到的。
我建议在更新数组时使用 @synchronized 来保护数组 -
- (void)tileCache:(RMTileCache *)tileCache didBackgroundCacheTile:(RMTile)tile withIndex:(NSUInteger)tileIndex ofTotalTileCount:(NSUInteger)totalTileCount {
DebugLog(@"Cached tile %lu of %lu.", (unsigned long)tileIndex, (unsigned long)totalTileCount);
if (_currentlyDownloading) {
float progress = (float)tileIndex / (float)totalTileCount;
NSDictionary *progressDict = @{@"progress" : [NSNumber numberWithFloat:progress],
@"routeId" : _downloadingRoute.routeId};
@synchronized(_currentTileHashes) {
[_currentTileHashes addObject:[RMTileCache tileHash:tile]];
}
[[NSNotificationCenter defaultCenter]
postNotificationName:@"routeTileDownloaded"
object:progressDict];
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
275 次 |
| 最近记录: |