我有一个非常大的NSDictionary,我想将数据添加到SQlite DB

时间:2015-11-26 12:33:23

标签: ios

这就是我在做的事情:

for(NSString *mydic in _grandDic) {
        NSMutableDictionary *db = [_grandDic valueForKey:mydic];
        for (NSString *Key in db) {
            NSMutableDictionary *dDic = [db objectForKey:Key];
            dispatch_sync(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
                 [self addUsingDic:dDic];
                dispatch_async(dispatch_get_main_queue(), ^(void){
                });
            });

        }
    }

如果函数addUsingDic:dDic非常大并且将数据插入到数据库中,那么当我使用此应用程序时,应用程序会在发出错误的一堆命令后崩溃,这应该是连续执行的:

  

malloc: * mach_vm_map(size = 1048576)失败(错误代码= 3)   * 错误:无法分配区域   ***在malloc_error_break中设置断点以进行调试

1 个答案:

答案 0 :(得分:1)

你内存不足。当使用块将这些操作添加到队列时,for循环正在执行添加队列对象的速度远远快于块上的代码可以执行的速率。这些分配将与块对象本身相关,而不是已经分配的字典数据。

在不知道_grandDic的数据大小和_grandDic中的每个键值对的情况下,我无法给出明确的答案。

使用分配工具查看分配了多少内存(或者在应用程序运行时检查Xcode中的cmd + 6选项卡可能就足够了)

此外,使用dispatch_sync似乎没什么意义。您没有获得任何后台线程效率,因为您正在等待它完成。除非它只是说您的数据库操作都在队列中发生,并且您想等待以避免数据突变问题。但如果是这种情况,只需将整个循环放在dispatch_sync块中,如下所示:

dispatch_sync(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
    for(NSString *mydic in _grandDic) {
        NSMutableDictionary *db = [_grandDic valueForKey:mydic];

        for (NSString *Key in db) {

            NSMutableDictionary *dDic = [db objectForKey:Key];
            [self addUsingDic:dDic];

            dispatch_async(dispatch_get_main_queue(), ^(void){
            });
        }
    }
});

如果你想要后台线程效率,请尝试:

    NSDictionary *gDic = [[NSDictionary alloc] initWithDictionary:_grandDic copyItems:YES];


dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(void){
    for(NSString *mydic in gDic) {
        NSMutableDictionary *db = [_grandDic valueForKey:mydic];

        for (NSString *Key in db) {

            NSMutableDictionary *dDic = [db objectForKey:Key];
            [self addUsingDic:dDic];

            dispatch_async(dispatch_get_main_queue(), ^(void){
            });
        }
    }
});

我制作了_grandDic的副本,因为否则您可能会遇到数据突变问题。我假设数据类型适用于深层副本,它们可能不是(如果所有数据都存储为NSString,例如它就可以了)。制作_grandDic的副本也可能会损害您的内存容量,在这种情况下,您需要将字典存储到磁盘并批量读取其内容。

或者,根据应用程序的设计以及在此方法返回后_grandDic的内容可能会更新的时间,可能可以不制作_grandDic的副本并直接使用它在方法中。然而,即使你非常清楚数据也不会被改变,这仍然是糟糕的设计和“hacky”,因为你给方法实现一个隐藏的依赖,它从它的'接口是不明显的。如果它们在私有方法中,有些人可能认为可以使用实例变量。我个人不会这样。