问题
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