ios - 在自己创建的多个线程中执行核心数据操作以节省处理时间

标签 ios objective-c multithreading core-data parallel-processing

我已经浏览了很多有关在多线程中执行核心数据操作的信息,但没有运气来解决我的问题。

我的代码是这样的,我必须每十分钟下载一个 csv 文件,其中包含每个 10 秒的条目。这个文件一旦下载就会被解析,内容被保存在数据库中,然后文件被删除,当需要时,我可以从数据库中获取数据。

现在,我现在有一个多月的大量现有内容,随着时间的推移可能会延长到数年,执行将新文件保存到数据库并将对象从核心数据提取到数组中的巨大任务已经使用单线程下载文件会导致大量处理时间。此外,应用中的 View 需要根据所有以前的数据进行调整(它们基本上是数量与时间的关系图)。

我如何在多线程中实现这一目标并优化我的代码处理时间并将 UI 阻塞降至最低?

请注意:在后台线程中执行任务与我无关,因为我无论如何都必须根据总数据显示图表。请提供宝贵意见。

编辑:执行了一些多线程 这是新代码,

- (void) downloadFiles:(NSString *)dataPath{



__block AppDelegate *appD = (AppDelegate *)[[UIApplication sharedApplication] delegate];

backgroundMOC = [[NSManagedObjectContext alloc] init];

[backgroundMOC setPersistentStoreCoordinator:[[appD managedObjectContext] persistentStoreCoordinator]];



if (parsedDetailsDataArrayForCurrentDay) {

    parsedDetailsDataArrayForCurrentDay = nil;

}



if (parsedDetailsDataArrayForCurrentMonth) {

    parsedDetailsDataArrayForCurrentMonth = nil;

}



if (parsedDetailsDataArrayForCurrentYear) {

    parsedDetailsDataArrayForCurrentYear = nil;

}

parsedDetailsDataArrayForCurrentDay = [[NSMutableArray alloc] init];

parsedDetailsDataArrayForCurrentMonth = [[NSMutableArray alloc] init];

parsedDetailsDataArrayForCurrentYear = [[NSMutableArray alloc] init];



dispatch_group_t d_group = dispatch_group_create();





for (NSInteger i = 0; i <= (self.filesListArray.count - 1); i++) {



    NSString *filePathOnPhone = [dataPath stringByAppendingString:[NSString stringWithFormat:@"/%@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]]];



    NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:@"ParsedInfiDetails"];



    NSString *nameToGet = [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"];



    NSLog(@"File Check: %@", nameToGet);

    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"fileName = %@", nameToGet];

    [fetch setPredicate:predicate];



    NSError *error = nil;



    NSArray *results = [backgroundMOC executeFetchRequest:fetch error:&error];



    NSArray *definedResults = [results copy];

    if(definedResults && (definedResults.count !=0)) {

        NSLog(@"Entities with that name: %@", results);

        @autoreleasepool {



            NSArray *result = [[definedResults sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modDate" ascending:YES]]] copy];



            NSDate *specificDate = [NSDate date];



            NSMutableArray *sortedDateArray = [[NSMutableArray alloc] init];

            NSMutableArray *sortedDateCurrentYearArray = [[NSMutableArray alloc] init];

            NSMutableArray *sortedDateCurrentMonthArray = [[NSMutableArray alloc] init];

            for (int i = 0; i < result.count; i++) {

                NSManagedObject *obj = [result objectAtIndex:i];

                NSDate *objDate = [obj valueForKey:@"modDate"];

                NSCalendar *gregorian = [NSCalendar currentCalendar];



                NSDateComponents *components = [gregorian componentsInTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"] fromDate:objDate];

                NSInteger day = [components day];

                NSInteger month = [components month];

                NSInteger year = [components year];



                NSDateComponents *specificComps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:specificDate];

                NSInteger specificDay = [specificComps day];

                NSInteger specificMonth = [specificComps month];

                NSInteger specificYear = [specificComps year];



                if(day == 24){



                }



                if (day == specificDay && month == specificMonth && year == (specificYear-2000)) {

                    [sortedDateArray addObject:obj];

                }



                NSDate *todayDate = [NSDate date];

                NSDateComponents *componentsForToday = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:todayDate];

                NSInteger currentMonth = [componentsForToday month];

                NSInteger currentYear = [componentsForToday year];





                if (year == (currentYear-2000)) {

                    [sortedDateCurrentYearArray addObject:obj];

                }



                if (year == (currentYear -2000) && month == currentMonth) {

                    [sortedDateCurrentMonthArray addObject:obj];

                }

            }



            NSMutableArray *sortedTimedArray = [[NSMutableArray alloc] initWithArray:[sortedDateArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];



            NSMutableArray *sortedTimedCurrentYearArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentYearArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];



            NSMutableArray *sortedTimedCurrentMonthArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentMonthArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];







            [parsedDetailsDataArrayForCurrentDay addObjectsFromArray:sortedTimedArray];

            [parsedDetailsDataArrayForCurrentYear addObjectsFromArray:sortedTimedCurrentYearArray];

            [parsedDetailsDataArrayForCurrentMonth addObjectsFromArray:sortedTimedCurrentMonthArray];

        }

    } else {

        NSLog(@"Error: %@", error);

        NSString *threadName = [NSString stringWithFormat:@"%ld THREAD", (long)i];

        dispatch_queue_t myQueue = dispatch_queue_create([threadName UTF8String], NULL);





        dispatch_group_async(d_group, myQueue, ^{

            NSManagedObjectContext *backgroundMOC1;

            backgroundMOC1 = [[NSManagedObjectContext alloc] init];

            [backgroundMOC1 setPersistentStoreCoordinator:[[appD managedObjectContext] persistentStoreCoordinator]];

            NSLog(@"Entered Thread ");



            BOOL success = [appD.ftpManager downloadFile:[[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"] toDirectory:[NSURL URLWithString:dataPath] fromServer:srv];



            if (success) {

//                dispatch_group_async(d_group, myQueue, ^{

                NSMutableDictionary *dict = [appD.ftpManager progress];

                NSString *filePath = [dataPath stringByAppendingString:[NSString stringWithFormat:@"/%@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]]];



                CHCSVParser *parser = [[CHCSVParser alloc] initWithContentsOfCSVURL:[NSURL fileURLWithPath:filePath]];

                [parser parse];

                NSMutableArray *currentFileComponentsArray = [NSArray arrayWithContentsOfCSVURL:[NSURL fileURLWithPath:filePath]];

                NSMutableArray *parsedDetailsEntitiesArray = [[NSMutableArray alloc] init];

                for (int j = 1; j <= (currentFileComponentsArray.count-1); j++) {





                    NSArray *detailsArray = [currentFileComponentsArray objectAtIndex:j];

                    if (!(detailsArray.count < 32)) {

                        NSManagedObject *parsedDetails = [NSEntityDescription

                                                          insertNewObjectForEntityForName:@"ParsedInfiDetails"

                                                          inManagedObjectContext:[appD managedObjectContext]];

                        NSString *totalDateString = [NSString stringWithFormat:@"%@ %@", [detailsArray objectAtIndex:0], [detailsArray objectAtIndex:1]];

                        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];

                        dateFormatter.dateFormat = @"dd/MM/yyyy HH:mm:ss";

                        NSTimeZone *gmt = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];

                        [dateFormatter setTimeZone:gmt];

                        NSDate *startDate = [dateFormatter dateFromString:totalDateString];

                        [parsedDetails setValue:startDate forKey:@"modDate"];

                        [parsedDetails setValue:startDate forKey:@"modTime"];

                        ———————————————————————PERFORM PARSEDDETAILS STATEMENTS----------------





                        NSError *error;



                        NSLog(@"Saved File in Database: %@", [[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"]);

                        NSLog(@"Saved thread");

                        if (![backgroundMOC1 save:&error]) {

                            NSLog(@"Whoops, couldn't save: %@", [error localizedDescription]);

                        }

                        else{

                            if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {

                                //if the download fails, we try to delete the empty file created by the stream.

                                [[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];

                                //when data is stored in coredata remove the downloaded file.

                            }

                            [parsedDetailsEntitiesArray addObject:parsedDetails];



                        }



                    }





                }

                NSSet *set = [[NSSet alloc] initWithArray:parsedDetailsEntitiesArray];

                [self.relevantInverId setValue:set forKey:@"infiDetails"];



                NSDate *specificDate = [NSDate date];

                @autoreleasepool {

                    NSMutableArray *sortedDateArray = [[NSMutableArray alloc] init];

                    NSMutableArray *sortedDateCurrentYearArray = [[NSMutableArray alloc] init];

                    NSMutableArray *sortedDateCurrentMonthArray = [[NSMutableArray alloc] init];



                    for (int i = 0; i < parsedDetailsEntitiesArray.count; i++) {

                        NSManagedObject *obj = [parsedDetailsEntitiesArray objectAtIndex:i];

                        NSDate *objDate = [obj valueForKey:@"modDate"];



                        NSCalendar *gregorian = [NSCalendar currentCalendar];



                        NSDateComponents *components = [gregorian componentsInTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"] fromDate:objDate];

                        NSInteger day = [components day];

                        NSInteger month = [components month];

                        NSInteger year = [components year];



                        NSDateComponents *specificComps = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:specificDate];

                        NSInteger specificDay = [specificComps day];

                        NSInteger specificMonth = [specificComps month];

                        NSInteger specificYear = [specificComps year];



                        if(day == 24){





                        }

                        if (day == specificDay && month == specificMonth && year == (specificYear-2000)) {

                            [sortedDateArray addObject:obj];

                        }



                        NSDate *todayDate = [NSDate date];

                        NSDateComponents *componentsForToday = [[NSCalendar currentCalendar] components:NSCalendarUnitDay | NSCalendarUnitMonth | NSCalendarUnitYear fromDate:todayDate];

                        NSInteger currentMonth = [componentsForToday month];

                        NSInteger currentYear = [componentsForToday year];





                        if (year == (currentYear-2000)) {

                            [sortedDateCurrentYearArray addObject:obj];

                        }



                        if (year == (currentYear-2000) && month == currentMonth) {

                            [sortedDateCurrentMonthArray addObject:obj];

                        }



                    }



                    NSMutableArray *sortedTimedArray = [[NSMutableArray alloc] initWithArray:[sortedDateArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];



                    [parsedDetailsDataArrayForCurrentDay addObjectsFromArray:sortedTimedArray];





                    NSMutableArray *sortedTimedCurrentYearArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentYearArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];



                    NSMutableArray *sortedTimedCurrentMonthArray = [[NSMutableArray alloc] initWithArray:[sortedDateCurrentMonthArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];







                    [parsedDetailsDataArrayForCurrentYear addObjectsFromArray:sortedTimedCurrentYearArray];

                    [parsedDetailsDataArrayForCurrentMonth addObjectsFromArray:sortedTimedCurrentMonthArray];

                }




//                                    });



            }



        });



    }







    BOOL isFileAlreadyPresent = [[NSFileManager defaultManager] fileExistsAtPath:filePathOnPhone];





}



NSMutableArray *sortedParsedDetailsArrayForCurrentDay = [[NSMutableArray alloc] initWithArray:[parsedDetailsDataArrayForCurrentDay sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"modTime" ascending:YES]]]];



NSDate *startDate ;

NSDate *endaDate;





dispatch_group_notify(d_group, dispatch_get_main_queue(), ^{

    dispatch_async(dispatch_get_main_queue(), ^{

        [self stopLogoSpin];

        [hud dismiss];



    });

    NSLog(@"All background tasks are done!!");

});


}

现在,日志 @"Entered Thread "在日志中可见,但 @"Saved File in Database: %@", [[self.filesListArray objectAtIndex:i] 和 @"Saved thread"未被调用。

此外,

BOOL success = [appD.ftpManager downloadFile:[[self.filesListArray objectAtIndex:i] objectForKey:@"kCFFTPResourceName"] toDirectory:[NSURL URLWithString:dataPath] fromServer:srv];

在下载方法中使用单独的线程帮助下载文件。 取消下面的评论会有帮助吗?

    //                dispatch_group_async(d_group, myQueue, ^{

主线程是有意等待的,但下面的这个 block 也从未被调用:

dispatch_group_notify(d_group, dispatch_get_main_queue(), ^{
    dispatch_async(dispatch_get_main_queue(), ^{
        [self stopLogoSpin];
        [radialHUD dismiss];

    });
    NSLog(@"All background tasks are done!!");
});

请指教以上问题的修改和解决方法。

最佳答案

通过将循环中不需要的所有内容移到外部并使用 GCD 执行循环操作来优化代码。

 dispatch_queue_t myOwnQueue = dispatch_queue_create([@"MyOwnQueue" UTF8String], NULL);

dispatch_apply(self.filesListArray.count, myOwnQueue, ^(size_t i) {   });

这导致时间减少了一半。然而,还需要进一步优化。

关于ios - 在自己创建的多个线程中执行核心数据操作以节省处理时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32393589/

相关文章:

c++ - QT:无法从另一个线程启用套接字通知程序

ios - 通过自定义表格单元设置值

ios - 将 UITableViewCell 的背景颜色设置为图案图像

ios - 如何阻止 UIImageView 中的图像缩放?

ios - 如何将 UIDatePicker 更改为特定时间(在代码中)

ios - 与 UITableView 具有相同背景的模糊导航栏

java - 线程和用户界面

java - 无法使用空消息确定 NetworkOnMainThreadException 的原因

ios - 为什么我收到错误 EXC_BAD_INSTRUCTION(代码=EXC_I386_INVOP,子代码=0x0)

UITableViewCell 和 heightForRowAtIndexPath 的 iOS 动态高度