UI Stucks in iOS app possible reason is FMDB query?

柔情痞子 提交于 2020-01-07 03:10:34

问题


my apps UI stuck for several seconds for the very first time app launches (MenuPage) and when I move to Account page. It stuck while calculating some status. But I did them in background queue. I paused and looked at the debugger. Its shows this:

I am giving the codes from account page as it is much clean than the menu page.

From account page I am calling SyncStatus like this:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [_syncStatus startStatusCalculating];
});

SyncStatus.h is:

#import <Foundation/Foundation.h>
#import "SyncStatusCalculatorOperation.h"

@interface SyncStatus : NSObject <SyncStatusOperationDelegate>

@property (nonatomic, strong) NSDictionary* syncStatusValues;
@property (nonatomic, strong) NSOperationQueue* syncStatusOperationQueue;

-(void) startStatusCalculating;
-(void) stopStatusCalculating;
-(void) forceCalculation;
-(void) startUpdateOperation;

@end

SyncStatus.m is:

#import "SyncStatus.h"
#import "SyncStatusCalculatorOperation.h"

@implementation SyncStatus {
    NSTimer *calculatorTimer;
    NSInteger cycleCount;
}

@synthesize syncStatusValues = _syncStatusValues;
@synthesize syncStatusOperationQueue = _syncStatusOperationQueue;

- (instancetype)init
{
    self = [super init];
    if (self) {
        cycleCount = 0;
        _syncStatusOperationQueue = [[NSOperationQueue alloc] init];
        _syncStatusOperationQueue.maxConcurrentOperationCount = 1;
    }
    return self;
}

-(void) forceCalculation {
    [self transmitData];
}

-(void) updateSyncStatusValues:(NSDictionary *) syncValues {
    self.syncStatusValues = syncValues;
    [self transmitData];
}

-(void) transmitData {
    if([self.syncStatusValues objectForKey:TOTAL_ROW] == nil){
        NSLog(@"no status info to send");
        return;
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:SYNC_STATUS_NOTIFICATION
                                                        object:nil
                                                      userInfo:self.syncStatusValues];
}

-(void) syncCalc {
    if (cycleCount < 3) {
        [self transmitData];
        cycleCount ++;
    }
    else {
        [self startUpdateOperation];
        cycleCount = 0;
    }
}

-(void) startUpdateOperation
{
    SyncStatusCalculatorOperation *syncOperation = [[SyncStatusCalculatorOperation alloc] initWithDelegate:self];
    [self.syncStatusOperationQueue addOperation:syncOperation];
}

-(void) startStatusCalculating {

    if (![calculatorTimer isValid]) {
        cycleCount = 3;
        calculatorTimer = [NSTimer scheduledTimerWithTimeInterval:5.0 target:self selector:@selector(syncCalc) userInfo:nil repeats:YES];
        [calculatorTimer fire];
    }
}

-(void) stopStatusCalculating {
    if([calculatorTimer isValid]){
        [calculatorTimer invalidate];
    }
    [self.syncStatusOperationQueue cancelAllOperations];
}

@end

SyncStatusCalculatorOperation.h:

#import <Foundation/Foundation.h>

@protocol SyncStatusOperationDelegate <NSObject>

-(void) updateSyncStatusValues:(NSDictionary *) syncValues;


@end


@interface SyncStatusCalculatorOperation : NSOperation

@property (nonatomic, assign) id <SyncStatusOperationDelegate> delegate;

- (id) initWithDelegate:(id<SyncStatusOperationDelegate>) theDelegate;

@end

And SyncStatusCalculatorOperation.m is this:

#import "SyncStatusCalculatorOperation.h"
#import "IssMANAppDelegate.h"
#import "MediaDAO.h"
#import "ISSManDBManager.h"

@implementation SyncStatusCalculatorOperation {
    BOOL isCalculating;
}

- (id) initWithDelegate:(id<SyncStatusOperationDelegate>) theDelegate {
    if(self = [super init]) {
        self.delegate = theDelegate;
        isCalculating = NO;
    }
    return self;
}
- (void)main {

    // 4
    @autoreleasepool {

        if (self.isCancelled == NO){
            [self updateStatus];
        }

    }
}

-(void)updateStatus {

    if(isCalculating)return;

    isCalculating = YES;
    NSMutableArray *tableList = [[NSMutableArray alloc] init];

    [[IssMANAppDelegate appDelegate].dbQueue inDatabase:^(FMDatabase *db) {
        FMResultSet *resultsSet = [db executeQuery:@"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"];
        while ([resultsSet next]){
            [tableList addObject:[resultsSet stringForColumn:@"name"]];
        }
        [resultsSet close];
    }];

    __block int totalRow = 0;
    __block int pendingRow = 0;
//    totalPhotoRow = 0;
    __block int pendingPhotoRow = 0;
    __block int pendingDataDownload = 0;
    __block int pendingPhotoDownload = 0;

    pendingPhotoRow = [MediaDAO getPendingUploadImages];
    for(int k=0;k<tableList.count;k++) {

        NSString* tableName = (NSString*) [tableList objectAtIndex:k];

        if([tableName isEqualToString:@"settings"])continue;
        if([tableName isEqualToString:@"sqlite_sequence"])continue;
        if([tableName isEqualToString:@"temp_purchased_transactions"])continue;
        if([tableName isEqualToString:@"latest_project_report_issue"])continue;
        if([tableName isEqualToString:@"role"])continue;
        if([tableName isEqualToString:@"event_type"])continue;
        if([tableName isEqualToString:@"rel_role_event_type_notification_type"])continue;
        if([tableName isEqualToString:@"rel_user_product"])continue;
        if([tableName isEqualToString:@"media_content"])continue;

        [[IssMANAppDelegate appDelegate].dbQueue inDatabase:^(FMDatabase *db) {
            NSString* sql = NULL;
            if([ISSManDBManager columnExists:@"status" inTableWithName:tableName andDB:db]) {

                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@ where status <> 'deleted'",tableName];
            }
            else if([ISSManDBManager columnExists:@"sender_status" inTableWithName:tableName andDB:db]) {

                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@ where sender_status <> 'deleted'",tableName];
            }
            else {

                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@",tableName];
            }

            FMResultSet *resultSet = [db executeQuery:sql];

            while([resultSet next]) {
                int rowCount = [resultSet intForColumn:@"C"];
                if([tableName isEqualToString:@"media_content"]) {
//                    totalPhotoRow += rowCount;
                }
                else {
                    totalRow += rowCount;
                }
            }

            if([ISSManDBManager columnExists:@"status" inTableWithName:tableName andDB:db]) {
                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@ WHERE is_dirty = 1 and status <> 'deleted'",tableName];
            }
            else if([ISSManDBManager columnExists:@"sender_status" inTableWithName:tableName andDB:db]) {
                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@ WHERE is_dirty = 1 and sender_status <> 'deleted'",tableName];
            }
            else {
                sql = [NSString stringWithFormat:@"SELECT COUNT(*) C FROM %@ WHERE is_dirty = 1",tableName];
            }
            resultSet = [db executeQuery:sql];

            while([resultSet next]) {
                NSInteger rowCount = [resultSet intForColumn:@"C"];
                pendingRow += rowCount;
            }
            [resultSet close];
        }];
    }

    [[IssMANAppDelegate appDelegate].dbQueue inDatabase:^(FMDatabase *db) {

        NSString* sql = NULL;
        sql = [NSString stringWithFormat:@"SELECT COUNT(media.pk_id) C \
               FROM media, media_content \
               WHERE \
               media.pk_id = media_content.media_pk_id AND \
               media_owner IN (SELECT pk_id FROM user) AND \
               media.status = 'active' AND \
               media.update_date_time > media_content.last_sync_time"];

        FMResultSet *resultingSet = [db executeQuery:sql];

        while ([resultingSet next]) {

            int rowCount = [resultingSet intForColumn:@"C"];
            pendingPhotoDownload += rowCount;
        }
        [resultingSet close];

        NSString *sqlQuery = [NSString stringWithFormat:@"SELECT COUNT(pk_id) C FROM rel_user_product"];
        FMResultSet *resultsSets = [db executeQuery:sqlQuery];


        while([resultsSets next]) {

            int rowCount = [resultsSets intForColumn:@"C"];
            pendingDataDownload += rowCount;
        }
        [resultsSets close];
    }];

    double ratio = 0.0;
    if(totalRow)ratio = (double)pendingRow / (double)totalRow * 100.0;

    ratio = floor(100.0 - ratio);
    double downloadRation = 0.0;
    if(pendingDataDownload) downloadRation = 100.0;

    isCalculating = NO;

    NSMutableDictionary* syncStatusDic = [[NSMutableDictionary alloc] init];
    [syncStatusDic setObject:[NSNumber numberWithInt:totalRow] forKey:TOTAL_ROW];
    [syncStatusDic setObject:[NSNumber numberWithInt:pendingRow] forKey:PENDING_ROW];
    [syncStatusDic setObject:[NSNumber numberWithInt:pendingPhotoRow] forKey:PENDING_PHOTO];
    [syncStatusDic setObject:[NSNumber numberWithInt:pendingDataDownload] forKey:PENDING_DATA_DOWNLOAD];
    [syncStatusDic setObject:[NSNumber numberWithInt:pendingPhotoDownload] forKey:PENDING_PHOTO_DOWNLOAD];

    [self.delegate updateSyncStatusValues: [NSDictionary dictionaryWithDictionary:syncStatusDic]]; // safe conversion from NSMutableDictionary to NSDictionary
}

@end

来源:https://stackoverflow.com/questions/33852420/ui-stucks-in-ios-app-possible-reason-is-fmdb-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!