我正在使用NSUrlSession下载JSON数据并且它正在工作,但我收到一个UI警告,AppDelegate只能被称为主线程,我不知道如何在这种情况下摆脱它。我尝试将AppDelegate行本身包装到main_queue语句中,但这没有任何区别,我假设我在这里做了一些根本上基本的错误,但我无法弄清楚到底是什么。
代码如下所示。
+(void)fetchPricelistAll:(int)pricelistId :(int)startAtRow :(int)takeNoOfRows;
{
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:priceListId = %d", pricelistId);
}
NSString *finalURL = [NSString stringWithFormat:@"https://xxx.yyy.com/zzz/zzz/zzz/%d?StartAtRow=%d&TakeNoOfRows=%d",pricelistId, startAtRow, takeNoOfRows];
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:finalURL]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:Transport error %@", error);
}
} else {
NSHTTPURLResponse *responseHTTP;
responseHTTP = (NSHTTPURLResponse *) response;
if(responseHTTP.statusCode != 200) {
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:Server Error %d", (int) responseHTTP.statusCode);
}
} else {
NSArray *priceListObjectArray = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:count = %lu", (unsigned long)[priceListObjectArray count]);
}
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSOperationQueue *prlQueue = [[NSOperationQueue alloc] init];
prlQueue.maxConcurrentOperationCount = 1;
NSPersistentContainer *container = appDelegate.persistentContainer;
NSArray *arrayOfArrays = [NWTillHelper splitIntoArraysOfBatchSize:priceListObjectArray :1000];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"YYYY-MM-dd'T'HH:mm:ss"];
for(NSArray *batch in arrayOfArrays) {
[prlQueue addOperationWithBlock:^{
[container performBackgroundTask:^(NSManagedObjectContext *context ) {
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
NSDictionary *priceListObjectDict = nil;
//Loop through the array and for each dictionary insert into local DB
for (id element in batch) {
priceListObjectDict = element;
NSString *currencyName = [priceListObjectDict objectForKey:@"currencyName"];
NSString *price = [priceListObjectDict objectForKey:@"price"];
NSString *priceIncTax = [priceListObjectDict objectForKey:@"priceIncTAX"];
NSString *validFrom = [priceListObjectDict objectForKey:@"validFromDate"];
NSString *validTo = [priceListObjectDict objectForKey:@"validToDate"];
NSString *itemId = [priceListObjectDict objectForKey:@"itemID"];
NSDate *validToDate = [dateFormat dateFromString:validTo];
NSDate *validFromDate = [dateFormat dateFromString:validFrom];
NSManagedObject *newPrlItem = Nil;
newPrlItem = [NSEntityDescription
insertNewObjectForEntityForName:@"PriceList"
inManagedObjectContext:context];
[newPrlItem setValue:itemId forKey:@"itemId"];
[newPrlItem setValue:validToDate forKey:@"validTo"];
[newPrlItem setValue:validFromDate forKey:@"validFrom"];
[newPrlItem setValue:price forKey:@"price"];
[newPrlItem setValue:priceIncTax forKey:@"priceIncTax"];
[newPrlItem setValue:currencyName forKey:@"currencyName"];
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchTillData:ItemId in loop = %@", itemId);
NSLog(@"WebServices:fetchTillData:newPrlItem = %@", newPrlItem);
NSLog(@"WebServices:fetchTillData:CoreData error = %@", error);
}
}
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Failure to save context: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
} else {
NSUserDefaults *tillUserDefaults = [NSUserDefaults standardUserDefaults];
[tillUserDefaults setInteger:1 forKey:@"hasPriceList"];
[tillUserDefaults synchronize];
}
[context reset];
}];
}];
}
}
}
}] resume];
}
错误消息如下所示
=================================================================
Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 43836, TID: 4857183, Thread name: (none), Queue name: NSOperationQueue 0x60c00023aac0 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4 NWMPos 0x00000001076ce5c2 __35+[WebServices fetchPricelistAll:::]_block_invoke + 610
5 CFNetwork 0x000000010f295208 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
6 CFNetwork 0x000000010f294a6d __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 147
7 Foundation 0x0000000109a189b7 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
8 Foundation 0x0000000109a1881a -[NSBlockOperation main] + 68
9 Foundation 0x0000000109a16cd6 -[__NSOperationInternal _start:] + 778
10 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
11 libdispatch.dylib 0x000000010ec42af4 _dispatch_block_invoke_direct + 592
12 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
13 libdispatch.dylib 0x000000010ec42af4 _dispatch_block_invoke_direct + 592
14 libdispatch.dylib 0x000000010ec42884 dispatch_block_perform + 109
15 Foundation 0x0000000109a12ce4 __NSOQSchedule_f + 342
16 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010ec43856 _dispatch_continuation_pop + 967
18 libdispatch.dylib 0x000000010ec41c86 _dispatch_async_redirect_invoke + 780
19 libdispatch.dylib 0x000000010ec491f9 _dispatch_root_queue_drain + 772
20 libdispatch.dylib 0x000000010ec48e97 _dispatch_worker_thread3 + 132
21 libsystem_pthread.dylib 0x000000010f1005a2 _pthread_wqthread + 1299
22 libsystem_pthread.dylib 0x000000010f10007d start_wqthread + 13
2017-10-30 14:40:51.252817+0800 NWMPos[43836:4857183] [reports] Main Thread Checker: UI API called on a background thread: -[UIApplication delegate]
PID: 43836, TID: 4857183, Thread name: (none), Queue name: NSOperationQueue 0x60c00023aac0 (QOS: UNSPECIFIED), QoS: 0
Backtrace:
4 NWMPos 0x00000001076ce5c2 __35+[WebServices fetchPricelistAll:::]_block_invoke + 610
5 CFNetwork 0x000000010f295208 __75-[__NSURLSessionLocal taskForClass:request:uploadFile:bodyData:completion:]_block_invoke + 19
6 CFNetwork 0x000000010f294a6d __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 147
7 Foundation 0x0000000109a189b7 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
8 Foundation 0x0000000109a1881a -[NSBlockOperation main] + 68
9 Foundation 0x0000000109a16cd6 -[__NSOperationInternal _start:] + 778
10 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
11 libdispatch.dylib 0x000000010ec42af4 _dispatch_block_invoke_direct + 592
12 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
13 libdispatch.dylib 0x000000010ec42af4 _dispatch_block_invoke_direct + 592
14 libdispatch.dylib 0x000000010ec42884 dispatch_block_perform + 109
15 Foundation 0x0000000109a12ce4 __NSOQSchedule_f + 342
16 libdispatch.dylib 0x000000010ec3d43c _dispatch_client_callout + 8
17 libdispatch.dylib 0x000000010ec43856 _dispatch_continuation_pop + 967
18 libdispatch.dylib 0x000000010ec41c86 _dispatch_async_redirect_invoke + 780
19 libdispatch.dylib 0x000000010ec491f9 _dispatch_root_queue_drain + 772
20 libdispatch.dylib 0x000000010ec48e97 _dispatch_worker_thread3 + 132
21 libsystem_pthread.dylib 0x000000010f1005a2 _pthread_wqthread + 1299
22 libsystem_pthread.dylib 0x000000010f10007d start_wqthread + 13
答案 0 :(得分:0)
尝试将AppDelegate行中的所有代码包装到main_queue
中+(void)fetchPricelistAll:(int)pricelistId :(int)startAtRow :(int)takeNoOfRows;
{
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:priceListId = %d", pricelistId);
}
NSString *finalURL = [NSString stringWithFormat:@"https://xxx.yyy.com/zzz/zzz/zzz/%d?StartAtRow=%d&TakeNoOfRows=%d",pricelistId, startAtRow, takeNoOfRows];
[[[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:finalURL]
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error != nil) {
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:Transport error %@", error);
}
} else {
NSHTTPURLResponse *responseHTTP;
responseHTTP = (NSHTTPURLResponse *) response;
if(responseHTTP.statusCode != 200) {
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:Server Error %d", (int) responseHTTP.statusCode);
}
} else {
NSArray *priceListObjectArray = [NSJSONSerialization JSONObjectWithData:data
options:0
error:NULL];
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchPriceList:count = %lu", (unsigned long)[priceListObjectArray count]);
}
dispatch_async(dispatch_get_main_queue(), ^{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication]delegate];
NSOperationQueue *prlQueue = [[NSOperationQueue alloc] init];
prlQueue.maxConcurrentOperationCount = 1;
NSPersistentContainer *container = appDelegate.persistentContainer;
NSArray *arrayOfArrays = [NWTillHelper splitIntoArraysOfBatchSize:priceListObjectArray :1000];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"YYYY-MM-dd'T'HH:mm:ss"];
for(NSArray *batch in arrayOfArrays) {
[prlQueue addOperationWithBlock:^{
[container performBackgroundTask:^(NSManagedObjectContext *context ) {
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy;
NSDictionary *priceListObjectDict = nil;
//Loop through the array and for each dictionary insert into local DB
for (id element in batch) {
priceListObjectDict = element;
NSString *currencyName = [priceListObjectDict objectForKey:@"currencyName"];
NSString *price = [priceListObjectDict objectForKey:@"price"];
NSString *priceIncTax = [priceListObjectDict objectForKey:@"priceIncTAX"];
NSString *validFrom = [priceListObjectDict objectForKey:@"validFromDate"];
NSString *validTo = [priceListObjectDict objectForKey:@"validToDate"];
NSString *itemId = [priceListObjectDict objectForKey:@"itemID"];
NSDate *validToDate = [dateFormat dateFromString:validTo];
NSDate *validFromDate = [dateFormat dateFromString:validFrom];
NSManagedObject *newPrlItem = Nil;
newPrlItem = [NSEntityDescription
insertNewObjectForEntityForName:@"PriceList"
inManagedObjectContext:context];
[newPrlItem setValue:itemId forKey:@"itemId"];
[newPrlItem setValue:validToDate forKey:@"validTo"];
[newPrlItem setValue:validFromDate forKey:@"validFrom"];
[newPrlItem setValue:price forKey:@"price"];
[newPrlItem setValue:priceIncTax forKey:@"priceIncTax"];
[newPrlItem setValue:currencyName forKey:@"currencyName"];
if ([NWTillHelper isDebug] == 1) {
NSLog(@"WebServices:fetchTillData:ItemId in loop = %@", itemId);
NSLog(@"WebServices:fetchTillData:newPrlItem = %@", newPrlItem);
NSLog(@"WebServices:fetchTillData:CoreData error = %@", error);
}
}
NSError *error = nil;
if (![context save:&error]) {
NSLog(@"Failure to save context: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
} else {
NSUserDefaults *tillUserDefaults = [NSUserDefaults standardUserDefaults];
[tillUserDefaults setInteger:1 forKey:@"hasPriceList"];
[tillUserDefaults synchronize];
}
[context reset];
}];
}];
}
});
}
}
}] resume];
}
答案 1 :(得分:0)
正如您所说,对UIApplication.delegate
的调用被视为用户界面的一部分,因此无法从后台线程访问。
由于您只需要对持久性容器的引用,我建议:
[[UIApplication delegate] persistentContainer]
之前创建一个指向dataTaskWithURL:
的局部变量,然后在块内使用该局部变量