Reputation: 957
This is what I am doing :
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){
});
});
}
}
Where the function addUsingDic:dDic
is very large and insert data into DB this should be excuted serially when I am using this the app is getting crash after bunch of orders giving an error:
malloc: * mach_vm_map(size=1048576) failed (error code=3) * error: can't allocate region *** set a breakpoint in malloc_error_break to debug
Upvotes: 0
Views: 78
Reputation: 3585
You ran out of memory. When using a block to add these operations to a queue your for loop is executing adding queue objects at a far faster rate than the code on the block can execute. These allocations will relate to the block objects themselves rather than your dictionary data, which is already allocated.
Without knowing the data size of _grandDic and each key value pair within _grandDic I can't give a definitive answer.
Use the allocations instrument to see how much memory is allocated (or checking the cmd+6 tab in Xcode while the app is running may be sufficient)
Additionally, there seems little point in using dispatch_sync as you have. You aren't gaining any background thread efficiency because you are waiting for it to complete. Unless its simply that your database operations are all happening on the queue and you want to wait to avoid data mutation issues. But if that is the case, just put the whole loop within your dispatch_sync block like so:
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){
});
}
}
});
If you want background thread efficiency try:
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){
});
}
}
});
I make a copy of _grandDic because otherwise you might have issues with data mutation. I'm assuming the data types are amenable to a deep copy which they may not be (if all the data is stored as NSString's for example it will be OK). Making a copy of _grandDic might also blow your memory allowance in which case you are looking at having to store the dictionary to disk and reading its contents in batches.
Alternatively, depending on the design of the app and when the contents of _grandDic might be updated after this method returns, it may be ok not to make a copy of _grandDic and to just use it directly in the method. However even if you are very clear the data will not be mutated that is still bad design and "hacky" because you are giving the method implementation a hidden dependency it is not obvious it has from its' interface. Some might consider it ok to play with instance variables that way if they are in a private method. Personally I wouldn't though.
Upvotes: 1