Threading crash in Google Analytics for iOS - ios

Using the Google Analytics library for iOS version 3.0.9, (and 3.0.x in general), we see a lot of crashes like the one below.
They appeared to occur randomly.
Exception Type: SIGBUS
Exception Codes: BUS_ADRALN at 0xe756c0
Crashed Thread: 19
Thread 19 Crashed:
0 libsystem_platform.dylib 0x39e02e18 0x39e01000 + 7704
1 CoreFoundation 0x2bfd0d6f 0x2bf92000 + 257391
2 CoreFoundation 0x2c0716a3 0x2bf92000 + 915107
3 CoreFoundation 0x2c070417 0x2bf92000 + 910359
4 CoreFoundation 0x2bfd4a0b 0x2bf92000 + 272907
5 Communicator 0x00714541 +[GAIUsageTracker trackTarget:action:] + 193
6 Communicator 0x007049b3 -[GAITrackerImpl send:] + 47
7 Communicator 0x00157b8d __66+[xxx]_block_invoke (xxx.m:305)
8 libdispatch.dylib 0x39ca58cb 0x39ca4000 + 6347
9 libdispatch.dylib 0x39caeda3 0x39ca4000 + 44451
10 libdispatch.dylib 0x39cafcd7 0x39ca4000 + 48343
11 libsystem_pthread.dylib 0x39e06e31 0x39e06000 + 3633

It turns out that the GAI library is not as thread-safe as it claims. We were able to fix our Google Analytics crashes by serializing the calls.
(void (^)(void))block = {
// your analytics call, eg
[[[GAI sharedInstance] defaultTracker] send:....];
};
static dispatch_queue_t theQueue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
theQueue = dispatch_queue_create("Analytics Queue", DISPATCH_QUEUE_SERIAL);
});
dispatch_async(theQueue, block);
So all calls to the tracker are executed in code blocks serialized on the same queue ("theQueue" above), which forces only one code block to execute at a time.

Related

Crashlytics Crash with NSOperationQueue (QOS: UNSPECIFIED)

I'm getting a crash, reported in Crashlytics, and I have no idea how to reproduce the error, It happens randomly so it's hard to debug it with Xcode. Any ideas?
Crashed: NSOperationQueue 0x280419200 (QOS: UNSPECIFIED)
0 libobjc.A.dylib 0x22c471430 objc_retain + 16
1 CoreFoundation 0x22d2b5888 __CFBasicHashAddValue + 1480
2 CoreFoundation 0x22d1e64ac CFDictionarySetValue + 260
3 Foundation 0x22dd04888 _encodeObject + 732
4 myAPI 0x1062b44b0 -[DataCore encodeWithCoder:] (DataCore.m:236)
5 myAPI 0x1062909c4 -[DataHandle encodeWithCoder:] (DataHandle.m:53)
6 Foundation 0x22dd04aa8 _encodeObject + 1276
7 Foundation 0x22dc69c6c +[NSKeyedArchiver archivedDataWithRootObject:] + 168
8 myAPI 0x106288a34 __77+[CachableObject addObjectToCache:withCacheName:withTTL:withCompletionBlock:]_block_invoke (CachableObject.m:162)
9 Foundation 0x22dd198bc NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK + 16
10 Foundation 0x22dc21ab8 -[NSBlockOperation main] + 72
11 Foundation 0x22dc20f8c -[__NSOperationInternal _start:] + 740
12 Foundation 0x22dd1b790 __NSOQSchedule_f + 272
13 libdispatch.dylib 0x22ccc16c8 _dispatch_call_block_and_release + 24
14 libdispatch.dylib 0x22ccc2484 _dispatch_client_callout + 16
15 libdispatch.dylib 0x22cc6582c _dispatch_continuation_pop$VARIANT$mp + 412
16 libdispatch.dylib 0x22cc64ef4 _dispatch_async_redirect_invoke + 600
17 libdispatch.dylib 0x22cc71a18 _dispatch_root_queue_drain + 376
18 libdispatch.dylib 0x22cc722c0 _dispatch_worker_thread2 + 128
19 libsystem_pthread.dylib 0x22cea517c _pthread_wqthread + 472
20 libsystem_pthread.dylib 0x22cea7cec start_wqthread + 4
Here is what the code in DataCore.m looks like
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:programFormatPlayInfo forKey:#"ProgramFormatPlayInfo"];
[coder encodeObject:bigScreenPlayInfo forKey:#"BigScreenPlayInfo"];
[coder encodeObject:pivotHandle forKey:#"PivotHandle"];
[coder encodeInteger:pivotDataLinkId forKey:#"PivotDataLinkId"];
[coder encodeInteger:viewContextId forKey:#"ViewContextId"];
[coder encodeBool:suppressImagePivot forKey:#"SuppressImagePivot"];
[coder encodeObject:attributeIds forKey:#"AttributeIds"];
[coder encodeObject:self.overflow forKey:#"Overflow"];
[coder encodeObject:self.cacheNameWithUser forKey:#"CacheNameWithUser"];
[coder encodeObject:self.metaData forKey:#"Metadata"];
}
and here is where I try to add an object to the cache,
not sure if it's failing to decode or something related to the background queue.
+ (void)addObjectToCache:(CachableObject*)object withCacheName:(NSString*)cacheName withTTL:(CacheTime)cacheTimeSeconds withCompletionBlock:(void(^)()) block {
CachableObject* theObject = object;
[_backgroundQueue addOperationWithBlock:^{
#autoreleasepool {
#try {
NSString * path = [CachableObject pathForCachedObject:cacheName];
NSDate * date = [NSDate date];
[object setCacheDate:date];
[object setTtlSeconds:[NSNumber numberWithInteger:cacheTimeSeconds]];
[object setApiVersion:APIVERSION];
// Add to NSCache
[[CachableObject objectCache] setObject:theObject forKey:cacheName];
// Add to file system
NSError* err = nil;
NSData * data = [NSKeyedArchiver archivedDataWithRootObject:theObject];
if (data) {
[data writeToFile:path options:NSDataWritingAtomic error:&err];
}
// Add to dynamic cache
unwrapObjectAndComplyWithClass(object, [DataHandle class], ^(id unwrappedObject) {
DataHandle *objectUnwrapped = unwrappedObject;
DataFrame *objectFrame = objectUnwrapped.frame;
for (NSString *eachDependencyName in objectFrame.dependencies) {
[[VVIDynamicCacheManager sharedManager]addDependencyToStore:eachDependencyName withCacheName:cacheName];
}
}, ^{
/*Not a data handle*/
});
} #catch (NSException* ex) {
NSLog(#"CachableObject: got an exception %#", ex);
} #finally {
if (block) {
block();
}
}
}
}];
}
Some thoughts here.
First, you're using #try/#catch. I believe that NSKeyedArchiver throws exceptions when it should actually return NSError objects. So, perhaps that's why you are doing it. But, you have to keep in mind that none of Apple's frameworks are guaranteed to be exception-safe. This means that catching exceptions can leave Apple's code (and, of course, your own) in inconsistent states that will prevent it from working correctly in the future.
I would strongly recommend either removing the #catch, or scoping it extremely tightly around the NSKeyedArchiver code, if that's why you are using it. This could be unintentionally introducing a variety of other bugs into your app.
Now, on to the specific crash. It's occurring in the runtime's memory management code. This points very strongly at heap corruption. This means you've got a pointer that doesn't point to a valid Objective-C object in memory. This can happen for many reasons, and is extremely common. The most common cause is known as a dangling pointer. However, it could also be caused by an over-release. And, I wouldn't be at all surprised if it is possible to use an #catch to trigger an over-release. (I know, I'm harping, but I've seen so many issues caused by this pattern)
What I generally recommend in these situations:
Look for other crashes that look heap-corruption-related
Try out Zombies in Instruments
Try malloc scribble, or guardmalloc, two other good memory debugging tools
It's hard, and often even impossible, to reason about heap corruption. Replicating the bug can also be impossible, as memory corruption is typically not deterministic.
So, just try to find and fix as many issues as you can. It's totally possible that one of them is responsible for a variety of crashes, one of which could be this one.

EXC_BAD_ACCESS (SIGBUS) on iOS

We are facing iOS crash issue in our one SDK library written in objective-c. This objective-c library is being invoked from swift app developed by our customer.
Following is the code snippet from our sdk, where we are creating multiple threads:-
//Create a queue to collect attributes in parallel
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
//Create group to wait on the task scheduled in global queue
dispatch_group_t group = dispatch_group_create();
// Collect all information1
dispatch_group_async(group, queue, ^{
info1 = [self getInformation1];
});
// Collect all information2
dispatch_group_async(group, queue, ^{
info2 = [self getInformation2];
});
// Collect all information3
dispatch_group_async(group, queue, ^{
info3 = [self getInformation3];
});
// Collect all information4
dispatch_group_async(group, queue, ^{
info4 = [self getInformation4];
});
// Collect all information5
dispatch_group_async(group, queue, ^{
info5 = [self getInformation5];
});
// wait on the group to block the current thread.
int64_t time_delay = 3.0;
dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, time_delay * NSEC_PER_SEC);
long success = dispatch_group_wait(group,timeout);
if(success != 0) {
//Log data to check which bucket is not complete
[Logger writeLogWithSeverity:kLogERROR message:info1];
[Logger writeLogWithSeverity:kLogERROR message:info2];
[Logger writeLogWithSeverity:kLogERROR message:info3];
[Logger writeLogWithSeverity:kLogERROR message:info4];
[Logger writeLogWithSeverity:kLogERROR message:info5];
}
Is this is ideal way or is there any better way to create concurrent threads?
Following are couple of stack traces of the crashes
1)
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x00000000 at 0x0000000323f7bec8
Crashed Thread: 0
Thread 0 Crashed:
0 libobjc.A.dylib 0x000000018193c1a0 0x181918000 + 147872 (objc_retain + 16)
1 abcMobile 0x0000000104365cbc 0x1041c8000 + 1694908 -[DeviceInventory notifyCollectingdeviceInfo:] (DeviceInventory.m:215 + 28)
2 abcMobile 0x0000000104365b78 0x1041c8000 + 1694584 -[DeviceInventory startCollectingdeviceInfo] (DeviceInventory.m:206 + 0)
3 libdispatch.dylib 0x0000000182058b24 0x182057000 + 6948 ( + 24)
4 libdispatch.dylib 0x0000000182058ae4 0x182057000 + 6884 ( + 16)
5 libdispatch.dylib 0x00000001820656e0 0x182057000 + 59104 ( + 1012)
6 CoreFoundation 0x000000018270f070 0x182621000 + 974960 ( + 12)
7 CoreFoundation 0x000000018270cbc8 0x182621000 + 965576 ( + 2272)
8 CoreFoundation 0x000000018262cda8 0x182621000 + 48552 (CFRunLoopRunSpecific + 552)
9 GraphicsServices 0x000000018460f020 0x184604000 + 45088 (GSEventRunModal + 100)
10 UIKit 0x000000018c60d78c 0x18c2f0000 + 3266444 (UIApplicationMain + 236)
11 abcMobile 0x00000001041ccc40 0x1041c8000 + 19520 main (main.swift:14 + 20)
12 libdyld.dylib 0x00000001820bdfc0 0x1820bd000 + 4032 ( + 4)
Crashing code :- [self.delegate didCompletedCollectingInformation:deviceInfo];
didCompletedCollectingInformation is a call-back function
2)
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: 0x00000000 at 0x00000007943dbec8
Crashed Thread: 18
Thread 18 Crashed:
0 libobjc.A.dylib 0x0000000182f3c1a0 0x182f18000 + 147872 (objc_retain + 16)
1 abcMobile 0x0000000100c0150c 0x100a64000 + 1692940 -[DeviceInventory didFailWithError:] (DeviceInventory.m:144 + 28)
2 CoreFoundation 0x0000000183cf8c3c 0x183c21000 + 883772 ( + 20)
3 CoreFoundation 0x0000000183cf81b8 0x183c21000 + 881080 ( + 428)
4 CoreFoundation 0x0000000183cf7f14 0x183c21000 + 880404 ( + 216)
5 CoreFoundation 0x0000000183d7584c 0x183c21000 + 1394764 ( + 1408)
6 CoreFoundation 0x0000000183c2ef38 0x183c21000 + 57144 (_CFXNotificationPost + 384)
7 Foundation 0x000000018469fbbc 0x184699000 + 27580 ( + 68)
8 abcMobile 0x0000000100bf7f80 0x100a64000 + 1654656 +[Errors sendErrorNotifactionForErrorCode:] (Errors.m:405 + 64)
9 abcMobile 0x0000000100bf101c 0x100a64000 + 1626140 +[NetworkInfo information1] (NetworkInfo.m:711 + 0)
10 abcMobile 0x0000000100bfb9fc 0x100a64000 + 1669628 -[Services information1] (Services.m:391 + 20)
11 abcMobile 0x0000000100c058b4 0x100a64000 + 1710260 -[DeviceInventory getInformation1] (DeviceInventory.m:635 + 56)
12 abcMobile 0x0000000100c0268c 0x100a64000 + 1697420 __39-[DeviceInventory getdeviceInfo]_block_invoke.163 (DeviceInventory.m:256 + 16)
13 libdispatch.dylib 0x0000000183658aa0 0x183657000 + 6816 ( + 24)
14 libdispatch.dylib 0x0000000183658a60 0x183657000 + 6752 ( + 16)
15 libdispatch.dylib 0x000000018369a5f0 0x183657000 + 275952 ( + 1148)
16 libdispatch.dylib 0x000000018369a110 0x183657000 + 274704 ( + 112)
17 libsystem_pthread.dylib 0x000000018398bfac 0x18398b000 + 4012 (_pthread_wqthread + 1176)
Crashing code :- if([self.delegate respondsToSelector:#selector(didFailWithError:)])
Here, didFailWithError is a call-back function
We are unable to find the root cause of this crash as it is very random issue. Does anyone have any idea how to fix this crash issue?
Any pointers will be very helpful as we are struck on this issue.

iOS Core Data dispatch_async background queuing crash

I'm getting a non-reproduceable crash and I'm not sure why. I'm caching images on a background queue. The image names are properties on a Core Data NSManagedObject subclass, CCCard. At the same time, I have a collection view that is also accessing these CCCards.
Here is the relevant code and notes to follow.
//CCDeckViewController.m --------------------------------------
- (void)viewDidLoad {
// This will fetch the CCCard objects from Core Data.
self.cards = [[CCDataManager shared] cards];
[self cacheImages];
}
- (void)cacheCardImages {
// Because these are NSManagedObjects, I access them in the background
// via their object ID. So pull the IDs out here.
NSArray *cardIds = [self.cards valueForKey:#"objectID"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
for (NSManagedObjectID *cardId in cardIds) {
// Fetch the actual CCCard object.
CCCard *card = (CCCard *)[[CCDataManager shared] objectWithId:cardId];
// Cache the card's image if it's not already there.
NSString *key = [card thumbnailCacheKey];
if ([self.cardImageCache objectForKey:key]) {
continue;
}
CCDiscardableImage *discardable = [CCHelper decompressedImageForPath:key size:[card thumbnailSize] tintable:[card tintable]];
[self.cardImageCache setObject:discardable forKey:key];
}
});
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CCCard *card = self.cards[indexPath.item];
// This line calls the code that crashes.
UIColor *color = [card color];
// More code that returns the cell.
}
// CCCard.m --------------------------------------
- (UIColor *)color {
// Crash happens on this line.
if (self.colorId.integerValue == 0) {
// some code
}
}
Here are parts of the stack trace from the Crashlytics report I think are most relevant:
Thread #0: Crashed: com.apple.main-thread
EXC_BREAKPOINT 0x000000000000defe
0 CoreData 0x24c1b070 _sharedIMPL_pvfk_core + 247
1 CoreData 0x24c1b071 _sharedIMPL_pvfk_core + 248
2 myapp 0x4286f -[CCCard color] (CCCard.m:37)
3 myapp 0x40bbb -[CCDeckViewController collectionView:cellForItemAtIndexPath:] (CCDeckViewController.m:127)
Thread #4: com.apple.root.utility-qos
0 libsystem_pthread.dylib 0x2321920c RWLOCK_GETSEQ_ADDR
1 libsystem_pthread.dylib 0x23219295 pthread_rwlock_unlock + 60
2 libobjc.A.dylib 0x22cb8e01 rwlock_tt<false>::unlockRead() + 8
3 libobjc.A.dylib 0x22cb5af5 lookUpImpOrForward + 488
4 libobjc.A.dylib 0x22cb5903 _class_lookupMethodAndLoadCache3 + 34
5 libobjc.A.dylib 0x22cbbd7b _objc_msgSend_uncached + 26
6 CoreData 0x24c1d3ab _PFObjectIDFastEquals64 + 38
7 CoreFoundation 0x233eeed4 CFBasicHashFindBucket + 1820
8 CoreFoundation 0x233ee775 CFDictionaryGetValue + 116
9 CoreData 0x24c17037 _PFCMT_GetValue + 122
10 CoreData 0x24c16ec7 -[NSManagedObjectContext(_NSInternalAdditions) _retainedObjectWithID:optionalHandler:withInlineStorage:] + 58
11 CoreData 0x24c1b45d _PF_FulfillDeferredFault + 940
12 CoreData 0x24c1afcf _sharedIMPL_pvfk_core + 86
13 myapp 0x42991 -[CCCard imagePath] (CCCard.m:53)
14 myapp 0x41d5b __39-[CCDeckViewController cacheCardImages]_block_invoke (CCDeckViewController.m:295)
It's frustrating because it never happens during development, so can't test any theories. I'm trying to understand the code and crash report to figure out the problem now. My guess is that it has something to do with faulting because it accesses the CCCard object's instance method, but then crashes when trying to read the property from it. But why?
You are violating thread confinement.
Per the Core Data documentation, a NSManagedObjectContext and any NSManagedObject associated with it must only be accessed on the queue that it is assigned to.
Your dispatch_async violates that rule and needs to be corrected. There is no longer a design where you can use Core Data in a dispatch_async like that.
If you want the processing to be asynchronous then you should spawn a private NSManagedObjectContext that is a child of your main NSManagedObjectContext and then execute a -performBlock: against it. That will give you background processing that is configured properly.
Also, I highly recommend turning on -com.apple.CoreData.ConcurrencyDebug 1 as that will catch issues like this during development.

Segfault from NSLog?

I'm seeing a segfault from using NSLog and specifically, it is on a 64 bit device, with a SEGV_ACCERR. I'm new to iOS, so i'm a little confused.
Here's the stack trace:
Exception Type: SIGSEGV
Exception Codes: SEGV_ACCERR at 0x108074000
Crashed Thread: 0
Thread 0 Crashed:
0 libsystem_platform.dylib 0x00000001826ea31c _platform_memmove + 300
1 libsystem_asl.dylib 0x00000001825289a4 asl_string_append_no_encoding_len + 92
2 libsystem_asl.dylib 0x0000000182522fc8 asl_string_new + 108
3 libsystem_asl.dylib 0x0000000182522df4 asl_msg_to_string_raw + 68
4 libsystem_asl.dylib 0x00000001825228dc _asl_send_message + 828
5 libsystem_asl.dylib 0x00000001825224fc asl_send + 8
6 CoreFoundation 0x0000000182a6fa1c __CFLogCString + 568
7 CoreFoundation 0x0000000182a6f7ac _CFLogvEx2 + 300
8 CoreFoundation 0x0000000182a6fc14 _CFLogvEx3 + 152
9 Foundation 0x0000000183435dd8 _NSLogv + 128
10 Foundation 0x000000018336ae04 NSLog + 28
Here is the code that calls this:
NSString *truncated = [NSString stringWithUTF8String:buffer];
// Using original NSLog to print.
#undef NSLog
NSLog(#"%#", truncated);
and it crashes from my NSLog call.
where buffer is just a char buffer.
My questions specifically are:
Is it even possible to crash from using Apple's provided NSLog? Or is my stack trace wrong?
What does SEG_ACCERR even mean in this context?
How could i go about finding if this was caused by a bad memory issue or not?
Is something blowing up with the asl file under multiple threads?
How should i approach debugging this?
Any help would be greatly appreciated! Thanks!
You say that buffer is a char buffer. If that is the case, you should initialize the string like this
NSString *truncated = [[NSString alloc] initWithBytes:buffer
length:len NSUTF8StringEncoding];
where len is the length of the characters in the buffer.

iOS screen become black little by little

I'm implementing an iOS app. and found that sometimes the screen became black little by little.
for example, in a view controller, there are a collection view, a button, a page controller, and sometimes I found the collection view became black(or invisible), only black background is shown, after 1-2 seconds, the button is gone, then the whole screen is black. but if I put the app into background, then bring it back, everything is ok.
here is the code:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSTimeInterval timeLeft = [UIApplication sharedApplication].backgroundTimeRemaining - 1.0;
if(timeLeft &lt 0)
{
completionHandler(UIBackgroundFetchResultNoData);
}
//create new thread to do something, and sleep at current thread
...create new threads
[NSThread sleep:timeLeft];
completionHandler(UIBackgroundFetchResultNewData);
});
}
the issue could be reproduced if I repeat the following actions several times:
Do some thing
Put app to background(press home button)
Bring app back to foreground
repeat 1 - 3
we found following error in organizer for our app:
: CoreAnimation: warning, deleted thread with uncommitted CATransaction; set CA_DEBUG_TRANSACTIONS=1 in environment to log backtraces.
after added , I got the following log:
Myapp[11496] : CoreAnimation: warning, deleted thread with uncommitted CATransaction; created by:
0 QuartzCore 0x31ca6a75 + 268
1 QuartzCore 0x31ca6929 + 224
2 QuartzCore 0x31cabddb + 86
3 QuartzCore 0x31cab9f7 + 150
4 UIKit 0x3203f919 + 344
5 UIKit 0x320bb11b + 138
6 UIKit 0x322b0ebf + 218
7 UIKit 0x322b1169 + 104
8 UIKit 0x322b1735 + 36
9 Myapp 0x002e538d __61-[AppDelegate application:performFetchWithCompletionHandler:]_block_invoke + 632
10 libdispatch.dylib 0x3a487d53 + 10
11 libdispatch.dylib 0x3a48d689 + 228
12 libdispatch.dylib 0x3a48d8dd + 56
13 libsystem_pthread.dylib 0x3a5b8c17 _pthread_wqthread + 298
14 libsystem_pthread.dylib 0x3a5b8adc start_wqthread + 8
my questions is:
how could application:performFetchWithCompletionHandler cause animation issue?
to answer questions:
1. I'm sure that phone is not going to sleep
2. source code. sorry the project is too big
Check that you are working with UI on main thread only, this should be the case.
Edit: - I've seen this one, although never used it(written by Peter Steinberger).
Also this answer can help avoiding several more problems.
The thread created to perform your fetch invokes a call to update your ui, when it finishes performing whatever task it is doing, and its no longer needed it is deallocated. UIUpdates MUST be performed on the main thread or they might not be performed right away.
Have you tried dispatching to the main thread whatever ui update you are performing there?
It's hard to know what you your completion handler is doing, but if it's updating UI try to dispatch them on the main thread
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSTimeInterval timeLeft = [UIApplication sharedApplication].backgroundTimeRemaining - 1.0;
if(timeLeft < 0)
{
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(UIBackgroundFetchResultNoData);
});
}
//create new thread to do something, and sleep at current thread
...create new threads
[NSThread sleep:timeLeft];
dispatch_async(dispatch_get_main_queue(), ^{
completionHandler(UIBackgroundFetchResultNewData);
});
});
}

Resources