取消 PFQuery 加载时间过长

Cancel PFQuery takes too much time to load

抱歉,我想不出更好的方式来描述我的 应用程序的功能。

我在 parse.com 的旧存档中找到了很多关于这个主题的帖子。尽管如此,它对我不起作用。在创建由 PFQuery.findObjects 触发的 PFQuery 实例之后(但 运行s 在后台线程上)我在请求过程中无法取消它。

场景:基本上我有一个连接到 Parse 的应用程序。我在 DataDisplay Screen 中显示了超过 100 条记录的数据,当用户单击后退按钮时它有一个后退按钮,如果 PFQuery.findObjects 仍然 运行 它在后台线程上然后我必须取消它。

我试过在 viewWillDisappear 中插入 PFQuery.cancel,但它无法停止,并且由于这些数据显示屏幕的 dealloc方法未调用。

我的代码,希望对您有所帮助:

- (void)loadANDSortingSongInformationWS {

if(ISINTERNET) {

    if(self.isShowLoadingForSkipSong)//Not Showing the activity indicator
        self.isShowLoadingForSkipSong = NO;

    else if(self.isFirstLoad || self.isAddPullToRefreshLikeSong)//Showing the indicator
        [self showHideLoading:YES];

    PFQuery *query = [PFQuery queryWithClassName:[UserPlaylistSongs parseClassName]];
    [query setLimit:1000];
    [query orderByDescending:@"createdAt"];
    [query whereKey:@"Playlist" equalTo:self.playlistInfo];
    [query includeKey:@"Playlist"];
    [query includeKey:@"Song"];
    [query includeKey:@"AddedBy"];
    [query includeKey:@"Host"];

    __weak typeof(self) weakSelf = self;

    [self.opearation addOperationWithBlock:^{

        [query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {

            if (objects.count == 0) {//No Songs Found

                //If there is no records
                dispatch_async(dispatch_get_main_queue(), ^{

                    [weakSelf showHideLoading:NO];

                    if(weakSelf.isFirstLoad || weakSelf.isAddPullToRefreshLikeSong) {//Problem while user pull to refresh when there is no song

                        [KSToastView ks_showToast:@"No Songs Found." duration:1.0f];
                    }
                });
            }

            else {//Songs Found

                dispatch_async(dispatch_get_main_queue(), ^{

                    NSMutableArray *arrParseSongList = [[NSMutableArray alloc] init];
                    __block NSInteger getTotalObjectsCount = 0;

                    for(NSInteger i=0; i<objects.count; i++) {

                        SongListInfo *songListData = [[SongListInfo alloc] init];
                        songListData.userPlaylistInfo = objects[i];

                        songListData.totLikes = [objects[i][@"Likes"] integerValue];
                        songListData.totDisLikes = [objects[i][@"Dislikes"] integerValue];
                        songListData.isPlaying = [objects[i][@"PlayingStatus"] boolValue];
                        songListData.songInfo = objects[i][@"Song"];
                        songListData.hostInfo = objects[i][@"Host"];
                        songListData.addedInfo = objects[i][@"AddedBy"];
                        songListData.playlistInfo = objects[i][@"Playlist"];
                        songListData.alreadyPlayedOrder = [objects[i][@"AlreadyPlayedIndex"] integerValue];
                        songListData.totRating = songListData.totLikes - songListData.totDisLikes;
                        songListData.createdDate = songListData.userPlaylistInfo.createdAt;

                        //User Specific for loading the song list.
                        PFQuery *queryLikeDislike = [PFQuery queryWithClassName:[SongLikeDislike parseClassName]];
                        [queryLikeDislike whereKey:@"SongID" equalTo:songListData.songInfo.objectId];
                        [queryLikeDislike whereKey:@"UserID" equalTo:[SINGLETON getUserID]];
                        [queryLikeDislike whereKey:@"PlaylistID" equalTo:songListData.playlistInfo.objectId];

                        [queryLikeDislike findObjectsInBackgroundWithBlock:^(NSArray *objectsLike, NSError *error) {

                            getTotalObjectsCount += 1;

                            if(error == nil) {

                                if(objectsLike.count) {

                                    BOOL isDelete = [objectsLike.lastObject[@"DeleteRecord"] boolValue];
                                    BOOL isLike = [objectsLike.lastObject[@"Like"] boolValue];

                                    if(isDelete)
                                        songListData.ratingType = RATING_GRAY;
                                    else if(isLike)
                                        songListData.ratingType = RATING_GREEN;
                                    else
                                        songListData.ratingType = RATING_RED;
                                }

                                else
                                    songListData.ratingType = RATING_GRAY;
                            }

                            else
                                NSLog(@"Problem while getting the rating type");

                            [arrParseSongList addObject:songListData];

                            NSLog(@"i : %ld, objects : %ld",(long)getTotalObjectsCount, (long)objects.count);
                            if(getTotalObjectsCount == objects.count)
                                [weakSelf processAfterGettingLikesAndDislikeInfo:arrParseSongList];
                        }];
                    }
                });
            }
        }];
    }];

    NSLog(@"In method -> All operation : %ld",(long)self.opearation.operations.count);
}

else
    [UIAlertView showErrorWithMessage:NO_INTERNET handler:nil];
}

- (void)processAfterGettingLikesAndDislikeInfo:(NSMutableArray *)arrParseSongList {

NSPredicate *filterGrayout = [NSPredicate predicateWithFormat:@"isPlaying == YES"];
NSArray *arrGrayOut = [arrParseSongList filteredArrayUsingPredicate:filterGrayout];

NSSortDescriptor *aSortDescriptorGrayedOut = [[NSSortDescriptor alloc] initWithKey:@"alreadyPlayedOrder.intValue" ascending:YES];
NSArray *arrGrayedOutSong = [NSMutableArray arrayWithArray:[arrGrayOut sortedArrayUsingDescriptors:[NSArray arrayWithObject:aSortDescriptorGrayedOut]]];

NSPredicate *filterNonPlay = [NSPredicate predicateWithFormat:@"isPlaying == NO"];
NSArray *arrNonPlay = [arrParseSongList filteredArrayUsingPredicate:filterNonPlay];

NSSortDescriptor *aSortDescriptorRating = [[NSSortDescriptor alloc] initWithKey:@"totRating.intValue" ascending:NO];
NSSortDescriptor *aSortDescriptorCreatedDate = [[NSSortDescriptor alloc] initWithKey:@"createdDate" ascending:YES];

NSArray *arrSortOnNormalSong = [NSMutableArray arrayWithArray:[arrNonPlay sortedArrayUsingDescriptors:[NSArray arrayWithObjects:aSortDescriptorRating,aSortDescriptorCreatedDate,nil]]];

if(self.arrSongsData.count)
    [self.arrSongsData removeAllObjects];

[self.arrSongsData addObjectsFromArray:arrGrayedOutSong];
[self.arrSongsData addObjectsFromArray:arrSortOnNormalSong];

[self showHideLoading:NO];
[self.tblView reloadData];
}

我在 viewWillDisappear 中调用。

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if(self.queryInstance)
       [self.queryInstance cancel];
}

感谢您的帮助!

所以有很多东西可能会将实例保存在内存中:

  1. 您正在向操作队列添加操作,并且这些操作会保留内容,因此仍在队列中的任何操作都会使控制器实例保持活动状态
  2. 你的完成块都在使用 self 而不是创建一个 __weak 引用并使用它,所以当块被保留时它是控制器实例
  3. 在完成第一个查询后,您将针对可能有 1000 个结果中的每一个开始另一个查询。这不仅会使网络充满请求,而且每个请求还会保留控制器实例
  4. 您可能有 1000 个查询 运行 未取消,具体取决于您尝试取消的确切时间

主要是,您应该在完成块中使用弱引用,这样当您尝试解除分配控制器时它就会消失并且查询的完成只是默默地 运行 在后台什么也没有。显然,如果用户不感兴趣,你确实想取消或阻止来自 运行 的所有 1000 个查询...