【问题标题】:Magical record Saving big amount of data to DB神奇的记录 将大量数据保存到数据库
【发布时间】:2014-08-03 09:48:39
【问题描述】:

我正在使用神奇的记录将大量数据保存到我的数据库中。我想将它保存在后台,但它冻结了 UI。我正在使用

保存它
[MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
    } completion:^(BOOL success, NSError *error) {
    }];

所以它不应该阻塞用户界面。但我发现它出于某些原因使用主线程来合并更改或类似的东西。如果有人可以提出如何提高效率的解决方案,我将不胜感激。

我正在使用的代码:

- (void)saveRidesForUser:(User *)user fromResponseData:(id)responseData
{

    if (![[[responseData valueForKey:@"rides"] class] isSubclassOfClass:[NSArray class]]) {
        return;
    }
    NSArray *rides = [responseData valueForKey:@"rides"];

    if (!rides)
        return;

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

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {

        User *rideUser = [user MR_inContext:localContext];

        for (NSDictionary *rideDictionary in rides) {

                Ride *ride = [Ride MR_createEntityInContext:localContext];
                ride.title = ([rideDictionary objectForKey:@"title"]) ? [rideDictionary valueForKey:@"title"] : @"";

                NSNumber *rideTimeStamp =[rideDictionary objectForKey:@"start_date"];
                if (rideTimeStamp)
                    ride.startDate = [NSDate dateWithTimeIntervalSince1970:[rideTimeStamp doubleValue]];

                NSNumber *rideEndTimeStamp =[rideDictionary objectForKey:@"end_date"];
                if (rideEndTimeStamp)
                    ride.endDate = [NSDate dateWithTimeIntervalSince1970:[rideEndTimeStamp doubleValue]];

                ride.serverID = [NSNumber numberWithInt:[[rideDictionary objectForKey:@"id"] intValue]];
                ride.isPopular = [NSNumber numberWithBool:NO];

                if ([rideDictionary objectForKey:@"intervals"]) {
                    NSArray *intervals = [rideDictionary objectForKey:@"intervals"];

                    for (NSDictionary *intervalDictionary in intervals) {

                        RideInterval *interval = [RideInterval MR_createEntityInContext:localContext];

                        interval.startDate = [NSDate dateWithTimeIntervalSince1970:[[intervalDictionary objectForKey:@"start_date"] integerValue]];
                        interval.endDate = [NSDate dateWithTimeIntervalSince1970:[[intervalDictionary objectForKey:@"end_date"] integerValue]];

                        interval.ride = ride;

                        if ([intervalDictionary objectForKey:@"points"] && ![[[intervalDictionary objectForKey:@"points"] class] isSubclassOfClass:[NSString class]]) {
                            NSArray *points = [intervalDictionary objectForKey:@"points"];

                            for (NSDictionary *pointDict in points) {

                                NSDictionary *pointDictionary = [pointDict dictionaryByReplacingNullsWithStrings];

                                RidePoint *point = [RidePoint MR_createEntityInContext:localContext];
                                point.timestamp = [NSDate dateWithTimeIntervalSince1970:[[pointDictionary objectForKey:@"timestamp"] integerValue]];

                                point.latitude = [NSNumber numberWithDouble:[[pointDictionary objectForKey:@"latitude"] doubleValue]];
                                point.longitude = [NSNumber numberWithDouble:[[pointDictionary objectForKey:@"longitude"] doubleValue]];
                                point.distanceFromPrevious = [NSNumber numberWithDouble:[[pointDictionary objectForKey:@"distance_from_previous"] doubleValue]];
                                point.interval = interval;
                            }
                        }
                    }
                }

                if ([rideDictionary valueForKey:@"photos"] && [[[rideDictionary valueForKey:@"photos"] class] isSubclassOfClass:[NSArray class]]) {
                    NSArray *photos = [rideDictionary objectForKey:@"photos"];

                    for (NSDictionary *photoDict in photos) {

                        NSDictionary *photoDictionary = [photoDict dictionaryByReplacingNullsWithStrings];
                        RidePhoto *photo = [RidePhoto MR_createEntityInContext:localContext];

                        photo.caption = [photoDictionary valueForKey:@"caption"];

                        NSNumber *timeStamp =[photoDictionary objectForKey:@"timestamp"];
                        if (timeStamp)
                            photo.timestamp = [NSDate dateWithTimeIntervalSince1970:[timeStamp doubleValue]];

                        photo.locationLatitude = [NSNumber numberWithDouble:[[photoDictionary objectForKey:@"location_latitude"] doubleValue]];
                        photo.locationLongitude = [NSNumber numberWithDouble:[[photoDictionary objectForKey:@"location_longitude"] doubleValue]];
                        photo.serverPath = [photoDictionary objectForKey:@"url"];
                        photo.imagePath = [NSString getUUID];
                        photo.ride = ride;

                        [photoCacheArray addObject:photo];
                    }
                }

                ride.user = rideUser;
            }

    } completion:^(BOOL success, NSError *error) {

        [[NSNotificationCenter defaultCenter] postNotificationName:kLTRideServise_RoutesDownloadedNotification object:nil userInfo:nil];

    }];

}

提前感谢您的帮助!

【问题讨论】:

    标签: ios objective-c core-data magicalrecord


    【解决方案1】:

    您是否将 MR_defaultContext 用于所有其他主线程任务?

    我正在使用 saveWithBlock: 方法进行后台保存, MR_defaultContext 用于主线程操作,它工作正常。据我所知,MagicalRecord 在保存操作结束时将 localContext 与 defaultContext 合并。

    示例代码:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.0 * NSEC_PER_SEC),      
    dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
            // your loop here in background thread
        } completion:^(BOOL success, NSError *error) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // completion on main thread
            });
        }];
    });
    

    【讨论】:

    • 是的,我就是这样做的。我保存了很多数据,这会是问题吗?
    • 检查 UI 何时开始冻结 - 在“for”循环期间、循环之后或整个保存块之后。
    • 用户界面在 for 循环之后立即冻结。关于如何解决这个问题的任何想法?
    • 我已经为您添加了带有 GCD 的示例代码。这应该可以完全消除您的流程中的冻结。
    • 不幸的是它完全一样。我读过 saveWithBlock 不应该这样使用。好吧,无论如何,我已经尝试过,但没有任何改变。还有其他解决方案吗?
    【解决方案2】:

    [[NSNotificationCenter defaultCenter] postNotificationName:kLTRideServise_RoutesDownloadedNotification object:nil userInfo:nil];

    ==> 完成后检查您正在进行的处理。此通知在主线程上调用,可能是您正在进行大量处理,导致主线程忙,导致 UI 冻结。

    还要检查您是否已从任何上下文注册 NSManagedObjectContextDidSaveNotification,并查看您是否正在那里进行任何处理。

    【讨论】:

      【解决方案3】:

      我正在使用

      [[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreWithCompletion:aCallback];

      将上下文保存到数据库中。

      它是这样记录的

      /// \brief 将当前上下文中的更改异步保存到持久存储 /// \param completion 保存完成后调用的完成块。如果发生错误,该块将作为“BOOL”和“NSError”实例传递成功状态。总是在主队列上调用。 /// \discussion 在当前上下文和任何祖先上执行异步保存,直到更改被持久化到分配的持久存储。完成块将始终在主队列上调用。

      这对我来说很好,没有任何冻结。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-14
        • 2014-02-24
        相关资源
        最近更新 更多