From 688345df80bb228e9c26b13ccec0710850223123 Mon Sep 17 00:00:00 2001 From: rowanbeentje Date: Mon, 12 Apr 2010 22:01:44 +0000 Subject: Review usage of notifications, afterDelay: and waitUntilDone:NO calls: - Add more calls to deregister watchers to fix crashes to closing threads or objects - Fix a couple of memory leaks - Alter a few calls to be performed on main thread (afterDelay: operates on the thread is is called on) - this fixed database reloading after import and field/index deletion error sheets --- Source/CMTextView.m | 15 +++------ Source/SPFieldEditorController.m | 1 + Source/SPNarrowDownCompletion.m | 1 + Source/SPQueryController.m | 1 + Source/SPSSHTunnel.m | 2 +- Source/SPTooltip.m | 1 + Source/TableContent.m | 2 +- Source/TableDocument.m | 5 ++- Source/TableDump.m | 2 +- Source/TableSource.m | 66 ++++++++++++++++++++++------------------ 10 files changed, 51 insertions(+), 45 deletions(-) (limited to 'Source') diff --git a/Source/CMTextView.m b/Source/CMTextView.m index 75839bc8..0b2ca6d3 100644 --- a/Source/CMTextView.m +++ b/Source/CMTextView.m @@ -2940,12 +2940,12 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) // Start autohelp only if the user really changed the text (not e.g. for setting a background color) if([prefs boolForKey:SPCustomQueryUpdateAutoHelp] && editedMask != 1) { - [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[[prefs valueForKey:SPCustomQueryAutoHelpDelay] retain] doubleValue]]; + [self performSelector:@selector(autoHelp) withObject:nil afterDelay:[[prefs valueForKey:SPCustomQueryAutoHelpDelay] doubleValue]]; } // Start autocompletion if enabled if([[NSApp keyWindow] firstResponder] == self && [prefs boolForKey:SPCustomQueryAutoComplete] && !completionIsOpen && editedMask != 1 && [textStore editedRange].length) - [self performSelector:@selector(doAutoCompletion) withObject:nil afterDelay:[[[prefs valueForKey:SPCustomQueryAutoCompleteDelay] retain] doubleValue]]; + [self performSelector:@selector(doAutoCompletion) withObject:nil afterDelay:[[prefs valueForKey:SPCustomQueryAutoCompleteDelay] doubleValue]]; // Cancel calling doSyntaxHighlighting for large text if([[self string] length] > SP_TEXT_SIZE_TRIGGER_FOR_PARTLY_PARSING) @@ -3281,15 +3281,8 @@ NSInteger alphabeticSort(id string1, id string2, void *reverse) - (void) dealloc { - if([prefs boolForKey:SPCustomQueryUpdateAutoHelp]) - [NSObject cancelPreviousPerformRequestsWithTarget:self - selector:@selector(autoHelp) - object:nil]; - - if([prefs boolForKey:SPCustomQueryAutoComplete]) - [NSObject cancelPreviousPerformRequestsWithTarget:self - selector:@selector(doAutoCompletion) - object:nil]; + // Cancel any deferred calls + [NSObject cancelPreviousPerformRequestsWithTarget:self]; // Remove observers [[NSNotificationCenter defaultCenter] removeObserver:self]; diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m index 6a481daa..cb4a11f7 100644 --- a/Source/SPFieldEditorController.m +++ b/Source/SPFieldEditorController.m @@ -113,6 +113,7 @@ - (void)dealloc { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; // On Mac OSX 10.6 QuickLook runs non-modal thus order out the panel // if still visible diff --git a/Source/SPNarrowDownCompletion.m b/Source/SPNarrowDownCompletion.m index 84568019..c76c06e6 100644 --- a/Source/SPNarrowDownCompletion.m +++ b/Source/SPNarrowDownCompletion.m @@ -141,6 +141,7 @@ - (void)dealloc { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; if(stateTimer != nil) { [stateTimer invalidate]; [stateTimer release]; diff --git a/Source/SPQueryController.m b/Source/SPQueryController.m index e1c85e68..c8906477 100644 --- a/Source/SPQueryController.m +++ b/Source/SPQueryController.m @@ -777,6 +777,7 @@ static SPQueryController *sharedQueryController = nil; - (void)dealloc { messagesVisibleSet = nil; + [NSObject cancelPreviousPerformRequestsWithTarget:self]; [dateFormatter release], dateFormatter = nil; diff --git a/Source/SPSSHTunnel.m b/Source/SPSSHTunnel.m index 968572c9..dfeb2f16 100644 --- a/Source/SPSSHTunnel.m +++ b/Source/SPSSHTunnel.m @@ -345,7 +345,7 @@ // On tunnel close, clean up [[NSNotificationCenter defaultCenter] removeObserver:self name:@"NSFileHandleDataAvailableNotification" - object:[standardError fileHandleForReading]]; + object:nil]; [task release], task = nil; [standardError release], standardError = nil; [taskEnvironment release], taskEnvironment = nil; diff --git a/Source/SPTooltip.m b/Source/SPTooltip.m index 3f8c2529..fc7133e2 100644 --- a/Source/SPTooltip.m +++ b/Source/SPTooltip.m @@ -240,6 +240,7 @@ static CGFloat slow_in_out (CGFloat t) - (void)dealloc { + [NSObject cancelPreviousPerformRequestsWithTarget:self]; [didOpenAtDate release]; [webView release]; [webPreferences release]; diff --git a/Source/TableContent.m b/Source/TableContent.m index 78e47b9a..82f2c39c 100644 --- a/Source/TableContent.m +++ b/Source/TableContent.m @@ -731,7 +731,7 @@ [tableDocumentInstance setTaskPercentage:(rowsProcessed*relativeTargetRowCount)]; } else if (rowsProcessed == targetRowCount) { [tableDocumentInstance setTaskPercentage:100.0]; - [tableDocumentInstance performSelectorOnMainThread:@selector(setTaskProgressToIndeterminateAfterDelay:) withObject:[NSNumber numberWithBool:YES] waitUntilDone:NO]; + [[tableDocumentInstance onMainThread] setTaskProgressToIndeterminateAfterDelay:YES]; } } diff --git a/Source/TableDocument.m b/Source/TableDocument.m index 71c581bf..b0465c0b 100644 --- a/Source/TableDocument.m +++ b/Source/TableDocument.m @@ -1282,7 +1282,8 @@ * Sets the task progress indicator back to indeterminate (also performed * automatically whenever a new task is started). * This can optionally be called with afterDelay set, in which case the intederminate - * switch will be made a fter a short pause to minimise flicker for short actions. + * switch will be made after a short pause to minimise flicker for short actions. + * Should be called on the main thread. */ - (void) setTaskProgressToIndeterminateAfterDelay:(BOOL)afterDelay { @@ -4050,6 +4051,8 @@ [prefs removeObserver:self forKeyPath:SPConsoleEnableLogging]; if (processListController) [prefs removeObserver:processListController forKeyPath:SPDisplayTableViewVerticalGridlines]; if (serverVariablesController) [prefs removeObserver:serverVariablesController forKeyPath:SPDisplayTableViewVerticalGridlines]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [NSObject cancelPreviousPerformRequestsWithTarget:self]; [_encoding release]; [allDatabases release]; diff --git a/Source/TableDump.m b/Source/TableDump.m index e056208c..4ae4743f 100644 --- a/Source/TableDump.m +++ b/Source/TableDump.m @@ -830,7 +830,7 @@ [tableDocumentInstance setDatabases:self]; // Update current selected database - [tableDocumentInstance performSelector:@selector(refreshCurrentDatabase) withObject:nil afterDelay:0.1]; + [[tableDocumentInstance onMainThread] refreshCurrentDatabase]; // Update current database tables [tablesListInstance updateTables:self]; diff --git a/Source/TableSource.m b/Source/TableSource.m index e80b7c43..69d5f393 100644 --- a/Source/TableSource.m +++ b/Source/TableSource.m @@ -913,16 +913,27 @@ closes the keySheet } } -/* - * Show Error sheet (can be called from inside of a endSheet selector) - * via [self performSelector:@selector(showErrorSheetWithTitle:) withObject: afterDelay:] +/** + * A method to show an error sheet after a short delay, so that it can + * be called from within an endSheet selector. This should be called on + * the main thread. */ --(void)showErrorSheetWith:(id)error +-(void)showErrorSheetWith:(NSDictionary *)errorDictionary { - // error := first object is the title , second the message, only one button OK - SPBeginAlertSheet([error objectAtIndex:0], NSLocalizedString(@"OK", @"OK button"), + + // If this method has been called directly, invoke a delay. Invoking the delay + // on the main thread ensures the timer fires on the main thread. + if (![errorDictionary objectForKey:@"delayed"]) { + NSMutableDictionary *delayedErrorDictionary = [NSMutableDictionary dictionaryWithDictionary:errorDictionary]; + [delayedErrorDictionary setObject:[NSNumber numberWithBool:YES] forKey:@"delayed"]; + [self performSelector:@selector(showErrorSheetWith:) withObject:delayedErrorDictionary afterDelay:0.3]; + return; + } + + // Display the error sheet + SPBeginAlertSheet([errorDictionary objectForKey:@"title"], NSLocalizedString(@"OK", @"OK button"), nil, nil, tableWindow, self, nil, nil, nil, - [error objectAtIndex:1]); + [errorDictionary objectForKey:@"message"]); } /** @@ -1751,11 +1762,10 @@ would result in a position change. // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { - - SPBeginAlertSheet(NSLocalizedString(@"Unable to remove relation", @"error removing relation message"), - NSLocalizedString(@"OK", @"OK button"), - nil, nil, [NSApp mainWindow], nil, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to remove the relation '%@'.\n\nMySQL said: %@", @"error removing relation informative message"), relationName, [mySQLConnection getLastErrorMessage]]); + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + [errorDictionary setObject:NSLocalizedString(@"Unable to remove relation", @"error removing relation message") forKey:@"title"]; + [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to remove the relation '%@'.\n\nMySQL said: %@", @"error removing relation informative message"), relationName, [mySQLConnection getLastErrorMessage]] forKey:@"message"]; + [[self onMainThread] showErrorSheetWith:errorDictionary]; } } @@ -1765,14 +1775,12 @@ would result in a position change. // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { - - [self performSelector:@selector(showErrorSheetWith:) - withObject:[NSArray arrayWithObjects:NSLocalizedString(@"Error", @"error"), - [NSString stringWithFormat:NSLocalizedString(@"Couldn't remove field %@.\nMySQL said: %@", @"message of panel when field cannot be removed"), - [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"Field"], - [mySQLConnection getLastErrorMessage]], - nil] - afterDelay:0.3]; + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + [errorDictionary setObject:NSLocalizedString(@"Error", @"error") forKey:@"title"]; + [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"Couldn't remove field %@.\nMySQL said: %@", @"message of panel when field cannot be removed"), + [[tableFields objectAtIndex:[tableSourceView selectedRow]] objectForKey:@"Field"], + [mySQLConnection getLastErrorMessage]] forKey:@"message"]; + [[self onMainThread] showErrorSheetWith:errorDictionary]; } else { [tableDataInstance resetAllData]; @@ -1819,11 +1827,10 @@ would result in a position change. // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { - - SPBeginAlertSheet(NSLocalizedString(@"Unable to remove relation", @"error removing relation message"), - NSLocalizedString(@"OK", @"OK button"), - nil, nil, [NSApp mainWindow], nil, nil, nil, nil, - [NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to remove the relation '%@'.\n\nMySQL said: %@", @"error removing relation informative message"), constraintName, [mySQLConnection getLastErrorMessage]]); + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + [errorDictionary setObject:NSLocalizedString(@"Unable to remove relation", @"error removing relation message") forKey:@"title"]; + [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"An error occurred while trying to remove the relation '%@'.\n\nMySQL said: %@", @"error removing relation informative message"), constraintName, [mySQLConnection getLastErrorMessage]] forKey:@"message"]; + [[self onMainThread] showErrorSheetWith:errorDictionary]; } } @@ -1837,11 +1844,10 @@ would result in a position change. // Check for errors, but only if the query wasn't cancelled if ([mySQLConnection queryErrored] && ![mySQLConnection queryCancelled]) { - - [self performSelector:@selector(showErrorSheetWith:) - withObject:[NSArray arrayWithObjects:NSLocalizedString(@"Unable to remove index", @"error removing index message"), - [NSString stringWithFormat:NSLocalizedString(@"An error occured while trying to remove the index.\n\nMySQL said: %@", @"error removing index informative message"), [mySQLConnection getLastErrorMessage]], nil] - afterDelay:0.3]; + NSMutableDictionary *errorDictionary = [NSMutableDictionary dictionary]; + [errorDictionary setObject:NSLocalizedString(@"Unable to remove index", @"error removing index message") forKey:@"title"]; + [errorDictionary setObject:[NSString stringWithFormat:NSLocalizedString(@"An error occured while trying to remove the index.\n\nMySQL said: %@", @"error removing index informative message"), [mySQLConnection getLastErrorMessage]] forKey:@"message"]; + [[self onMainThread] showErrorSheetWith:errorDictionary]; } else { [tableDataInstance resetAllData]; -- cgit v1.2.3