I am getting leak at [pool release];
My code here is:
#pragma mark UISearchBarDelegate delegate methods
- (void)performSearch:(UISearchBar *)aSearchBar
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
artistName= [aSearchBar.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if ([artistName length] > 0)
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
LyricsAppDelegate* appDelegate = (LyricsAppDelegate*) [ [UIApplication sharedApplication] delegate];
artistsList=[appDelegate doSearch:artistName ];
[theTableView reloadData];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[aSearchBar resignFirstResponder];
}
else
{
[aSearchBar resignFirstResponder];
}
[NSThread exit];
[pool release];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)aSearchBar
{
#try {
[NSThread detachNewThreadSelector:#selector(performSearch:) toTarget:self withObject:aSearchBar];
[aSearchBar resignFirstResponder];
}
#catch (NSException * e) {
NSLog(#"\n caught an exception");
}
#finally {
}
}
Here I am getting leak at [pool release]; in performSearch method.
How can I solve this.
Anyone's help will be much appreciated.
Thank you,
Monish.
Try to release pool before you exit current thread?
...
[pool release];
[NSThread exit];
Edit: From NSThread -exit reference:
Invoking this method should be avoided
as it does not give your thread a
chance to clean up any resources it
allocated during its execution.
Do you really need to call this function BTW?
In addition to Vladimir's answer pointing out the autorelease pool leak, both artistName & artistList are missing a release message before you set them to a new value (otherwise the old object is leaked), and a retain message afterwards (so the new object sticks around when the autorelease pool is drained).
[artistsList release];
artistsList = [[appDelegate doSearch:artistName] retain];
Related
So here's my problem: I've created a custom AVCaptureSession that takes pictures. I'm not sure why, but the third time you call startRunning, it crashes. I implemented didReceiveMemoryWarning, and it wasn't called before it crashed. I also ran instruments on it and there were no memory leaks associated with the AVCaptureSession. There were also no logs via console in XCode.
So my question is... is it a memory problem even though the didReceiveMemoryWarning wasn't called? Here's some of my code.
viewWillDisappear (ViewController)
- (void)viewWillDisappear:(BOOL)animated {
if (cameraFlashButton) { [cameraFlashButton release]; }
if (switchCamera) { [switchCamera release]; }
if (cameraBadgeBack) { [cameraBadgeBack release]; }
if (cameraBadgeNumber) { [cameraBadgeNumber release]; }
if (cameraUseButton) { [cameraUseButton release]; }
if (cameraOverlayView) { [cameraOverlayView release]; }
if (blackOverlay) { [blackOverlay release]; }
if (loadingIndicator) { [loadingIndicator release]; }
if (cameraPickButton) { [cameraPickButton release]; }
if (whiteOverlay) { [whiteOverlay release]; }
if (imageOverlay) { [imageOverlay release]; }
if (captureManager) { [captureManager release], captureManager = nil; }
if (theCaptureSession) { [theCaptureSession release], theCaptureSession = nil; }
[super viewWillDisappear:YES];
}
dealloc (CaptureSessionManager)
- (void)dealloc {
if ([self captureSession]) { [[self captureSession] stopRunning]; }
if (previewLayer) { [previewLayer release], previewLayer = nil; }
if (captureSession) { [captureSession release], captureSession = nil; }
if (stillImageOutput) { [stillImageOutput release], stillImageOutput = nil; }
if (stillImage) { [stillImage release], stillImage = nil; }
[super dealloc];
}
Ideas? If you need to see anything else, just ask! Thanks in advance.
If didReceiveMemoryWarning was properly implemented and it was never called, your problem is likely not due to running out of memory. There are many other ways you can get a crash when you start your capture session running. You'd need to post more of your implementation along with details of the crash to help debug this.
However, the code you posted has a number of inefficiencies and style problems. Note in Objective-C messages to nil are perfectly fine. So in your viewWillDisappear and dealloc methods you can and should remove every if test readability. For example, instead of:
if (cameraFlashButton) { [cameraFlashButton release]; }
just use:
[cameraFlashButton release];
If you are using properly synthesized accessors it is also much better to replace lines like
if (previewLayer) { [previewLayer release], previewLayer = nil; }
with simply
self.previewLayer = nil;
I'm using an NSOperation to collect data that should be downloaded (takes 2-5 sec.) and afterwards I download this. I've put a ASINetworkQueue inside this NSOperation to start downloading the previously collected data.
Everything works fine but when I call cancelAllOperations on my ASINetworkQueue, the main thread blocks and the UI Freezes. Why is this happening? Everything else works fine.
Here is my Code:
- (void)main {
//ManagedObjectContext for operations
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = [[NSManagedObjectContext alloc] init];
[self.managedObjectContext setPersistentStoreCoordinator: [appDelegate persistentStoreCoordinator]];
// Register context with the notification center
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self
selector:#selector(mergeChanges:)
name:NSManagedObjectContextDidSaveNotification
object:self.managedObjectContext];
[self startDownload];
if (!self.downloadDidFail) {
[self moveFiles];
[self.managedObjectContext save:nil];
}
}
- (void)startDownload {
self.downloadQueue = [ASINetworkQueue queue];
self.downloadQueue.delegate = self;
[self.downloadQueue setRequestDidFailSelector:#selector(dataRequestFailed:)];
[self.downloadQueue setRequestDidFinishSelector:#selector(dataRequestFinished:)];
[self.downloadQueue setQueueDidFinishSelector:#selector(dataQueueFinished:)];
[self.downloadQueue setShouldCancelAllRequestsOnFailure:YES];
[self.downloadQueue setDownloadProgressDelegate:self.progressView];
for (File *dataFile in self.dataFiles) {
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:dataFile.url]];
[request setDownloadDestinationPath:dataFile.path];
[self.downloadQueue addOperation:request];
}
}
[self.downloadQueue go];
[self.downloadQueue waitUntilAllOperationsAreFinished];
}
- (void)dataRequestFinished:(ASIHTTPRequest *)request {
NSLog(#"DL finished");
}
- (void)dataRequestFailed:(ASIHTTPRequest *)request {
DLog(#"Download failed");
self.downloadDidFail = YES;
}
- (void)dataQueueFinished:(ASINetworkQueue *)queue {
DLog(#"Finished Data Queue");
}
- (void)cancelDownload {
self.canceledDownload = YES;
[self.downloadQueue cancelAllOperations];
}
I had the same problem and solved by calling:
[queue setShouldCancelAllRequestsOnFailure:NO]
before calling:
[queue cancelAllOperations].
ASI requests responses and queue responses are deliberately moved to the main thread for library design purposes.
You have two solution:
-Subclass ASIHTTPRequest and overwrite 2 methods. (Look for in the code something like "subclass for main thread").
-Modify the library. (Easy, but personally I don't like this solution).
What does your failure delegate method do? ASIHTTPRequest will run that on the main thread by default, so if it does a lot of processing (or there are a lot of requests) this could take quite some time.
I have an app that uses NSOperationQueue intensively.
Sometimes I've noticed that some of the NSOperationQueues would "lock up" or enter a "isSuspended" state randomly even though my code never calls the setSuspended: method.
It's impossible to replicate and very hard to debug because whenever I hook the device up to Xcode to debug it, the app would reload and the bug would go away.
I added a lot of NSLogs at all possible points that might have a problem and just had to use the app for a few days until the bug reemerged.
Looking at the device system logs, I've discovered that [myOperationQueue operationCount] would increment but the opeations in queue will not execute.
I haven't tried manually setting "setSuspended:NO" yet but is that really necessary?
What could be causing this?
Here is a little bit of my code
The view controller that calls operations
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
self.operationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.operationQueue setMaxConcurrentOperationCount:2];
self.sendOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.sendOperationQueue setMaxConcurrentOperationCount:2];
self.receiveOperationQueue = [[[NSOperationQueue alloc] init] autorelease];
[self.receiveOperationQueue setMaxConcurrentOperationCount:1];
}
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[operationQueue cancelAllOperations];
[sendOperationQueue cancelAllOperations];
[receiveOperationQueue cancelAllOperations];
[operationQueue release];
[sendOperationQueue release];
[receiveOperationQueue release];
}
- (IBAction)sendMessage
{
if(![chatInput.text isEqualToString:#""])
{
NSString *message = self.chatInput.text;
SendMessageOperation *sendMessageOperation = [[SendMessageOperation alloc] initWithMatchData:matchData andMessage:message resendWithKey:nil];
[self.sendOperationQueue addOperation:sendMessageOperation];
[sendMessageOperation release];
}
}
NSOperation subclass SendMessageOperation
- (id)initWithMatchData:(MatchData*)data andMessage:(NSString*)messageString resendWithKey:(NSString*)resendKey
{
self = [super init];
if(self != nil)
{
if(data == nil || messageString == nil)
{
[self release];
return nil;
}
appDelegate = (YongoPalAppDelegate *) [[UIApplication sharedApplication] delegate];
context = [[NSManagedObjectContext alloc] init];
[context setPersistentStoreCoordinator:[appDelegate persistentStoreCoordinator]];
[context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(mergeContextChanges:) name:NSManagedObjectContextDidSaveNotification object:context];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(mergeMainContextChanges:) name:NSManagedObjectContextDidSaveNotification object:appDelegate.managedObjectContext];
self.matchData = (MatchData*)[context objectWithID:[data objectID]];
matchNo = [[matchData valueForKey:#"matchNo"] intValue];
partnerNo = [[matchData valueForKey:#"partnerNo"] intValue];
self.message = messageString;
self.key = resendKey;
apiRequest = [[APIRequest alloc] init];
}
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
self.matchData = nil;
self.message = nil;
self.key = nil;
[context release];
[apiRequest release];
[super dealloc];
}
- (void)start
{
if([self isCancelled] == YES)
{
[self willChangeValueForKey:#"isFinished"];
finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
else
{
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self main];
[self didChangeValueForKey:#"isExecuting"];
}
}
- (void)main
{
#try
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
bool taskIsFinished = NO;
while(taskIsFinished == NO && [self isCancelled] == NO)
{
NSDictionary *requestData = nil;
if(key == nil)
{
requestData = [self sendMessage];
}
else
{
requestData = [self resendMessage];
}
NSDictionary *apiResult = nil;
if(requestData != nil)
{
apiResult = [self sendMessageToServer:requestData];
}
if(apiResult != nil)
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"shouldConfirmSentMessage" object:nil userInfo:apiResult];
}
taskIsFinished = YES;
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
finished = YES;
executing = NO;
[self didChangeValueForKey:#"isFinished"];
[self didChangeValueForKey:#"isExecuting"];
[pool drain];
}
#catch (NSException *e)
{
NSLog(#"Exception %#", e);
}
}
- (BOOL)isConcurrent
{
return YES;
}
- (BOOL)isFinished
{
return finished;
}
- (BOOL)isExecuting
{
return executing;
}
- (void)mergeContextChanges:(NSNotification *)notification
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"mergeChatDataChanges" object:nil userInfo:[notification userInfo]];
}
- (void)mergeMainContextChanges:(NSNotification *)notification
{
NSSet *updated = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];
for(NSManagedObject *thing in updated)
{
[[context objectWithID:[thing objectID]] willAccessValueForKey:nil];
}
[context mergeChangesFromContextDidSaveNotification:notification];
}
You're using:
setMaxConcurrentOperationCount:X
My hunch is that X operations in the queue have not finished, therefore causing any subsequent operations added to the queue to not run until this is the case.
From the NSOperationQueue's isSuspended method documentation:
If you want to know when the queue’s suspended state changes, configure a KVO observer to observe the suspended key path of the operation queue.
Another idea that you can implement in parallel with the observer is to create a subclass of NSOperationQueue that redefines the setSuspended: method. In the redefined version you can set a breakpoint if you are running on the debugger, or print a stacktrace to the log if you are running w/o debugger.
Hope this helps.
take a look at ASIHTTPRequestConfig.h, it has some flags that you can turn on to see what is really happening behind the scenes.
I'm trying to add a spinning activity indicator (UIActivityIndicatorView) to my app while it parses data from the internet. I have an IBOutlet (spinner) connected to a UIActivityIndicatorView in IB. Initially I had it set up like this:
-
(void) function {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[spinner startAnimating];
//parse data from internet
[spinner stopAnimating];}
But the spinner wouldn't spin. I read that it had something to do with everything being on the same thread. So I tried this:
- (void) newFunction {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[spinner startAnimating];
[NSThread detachNewThreadSelector: #selector(function) toTarget: self withObject: nil];
[spinner stopAnimating];}
But still no luck. Any ideas? Thanks.
Your newFunction: method should look like this:
- (void) newFunction {
self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
self.spinner.hidesWhenStopped = YES;
[NSThread detachNewThreadSelector: #selector(function) toTarget: self withObject: nil];
}
And your function method should look like this:
- (void) function {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self.spinner performSelectorOnMainThread:#selector(startAnimating) withObject:nil waitUntilDone:NO];
//...
[self.spinner performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:NO];
[pool drain];
}
you should not intitialize indicator again .please replace your code with this.
-(void) function {
[spinner startAnimating];
[self performSelector:#selector(newfunction) withObject:nil afterDelay:3.0];
}
- (void) newfunction {
[spinner stopAnimating];
}
Thanks.
Just see that the "//parse data from internet " is synchronous or asynchronous. Asynchronous would mean that a separate thread would start from that point on, and the current function execution will continue without delay.
In your second example, you are explicitly making separate thread, which means that #selector(function) will happen on a separate thread, and the next statement [spinner stopAnimating] is executed immediately. So, it seems like spinner is not spinning at all.
Moreover, make sure you start and stop the activity indicator on main thread only.
I am getting the leak at this allocation
filteredListContent = [[NSMutableArray alloc] initWithCapacity:[showList count]];
CODE:
-(void)reloadTable
{
EventListAppDelegate *appDelegate;
UIApplication app = [UIApplication sharedApplication];
appDelegate = (EventListAppDelegate *)[app delegate];
contactList = [appDelegate getAllContactsList];
inviteeList = [appDelegate getInviteeListForEvent:event.primaryKey];
if (isInvited == YES)
{
showList = [appDelegate getInviteeListForEvent:event.primaryKey];
}
else
{
showList = [appDelegate getAllContactsList];
}
filteredListContent = [[NSMutableArray alloc] initWithCapacity:
[showList count]];
[filteredListContent addObjectsFromArray: showList];
[self organizeContactItemsIntoIndexes];
self.title = [event.name capitalizedString];
[self getToolbar];
[theTableView reloadData];
}
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[filteredListContent removeAllObjects];
ContactDTO *currentElement;
NSRange range;
for (currentElement in showList)
{
range = [currentElement.lastName rangeOfString:searchText
options:NSCaseInsensitiveSearch];
if(range.location == 0)
{
[filteredListContent addObject:currentElement];
}
}
[self organizeContactItemsIntoIndexes];
[theTableView reloadData];
}
- (void)dealloc
{
[filteredListContent release];
[super dealloc];
}
Your code will allocate a new instance of filteredListContent every time reloadTable is called, which will usually happen several times during the lifetime of your application. This causes a leak because the old instances are not released.
The best (and easiest) way to fix it would be to make filteredListContent a retain property:
in your class header:
#property (nonatomic, retain) NSMutableArray * filteredListContent;
in your reloadTable method:
self.filteredListContent = [NSMutableArray arrayWithCapacity:[showList count]];
Note the use of self. in the second code snippet. That syntax informs Cocoa that it should use the property accessor to set the value of filteredListContent, which will then send the appropriate retain and release messages for you.
You've posted three nearly-identical questions pertaining to memory leaks. It might be helpful for you to read through Apple's Memory Management Programming Guide.