Whenever I am trying to update the UIActivityIndicatorView from a thread, the app is getting crashed by throwing an exception
modifying layer that is being finalized - 0x7e177fd0
-[CALayer removeAnimationForKey:]: message sent to deallocated instance 0x7e177fd0
When I try tracking the memory leaks form the mallocDebugger tool, this crash is not happening at all the time happening 1 out of 10
please help me out from this memory issue
Thread implementation:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
[autoRechargeCell addSubview:activityIndicator];
[self.activityIndicator startAnimating];
if( [PennyTalkAPI getBalanceInfoForAccount:appDelegate.accountNumber withPIN:appDelegate.pinNumber])
{
[autoRechargeCell.switchField setOn:[[NSUserDefaults standardUserDefaults] boolForKey:#"AutoRecharge"]];
[self.activityIndicator stopAnimating]; <<<<<<<<<<<<<<<<<<<<<<
}
else
{
[self.activityIndicator stopAnimating];
}
[pool release];
This is the code I have written.
See this.
add [[NSNotificationCenter defaultCenter] removeObserver:self]; to UIActivityIndicatorView+AFNetworking.m dealloc
https://github.com/AFNetworking/AFNetworking/issues/2748
You are updating it from secondary thread that why it is crashing call this on main thread like
[self.activityIndicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:NO];
I think it may help you ....
Related
I want to do some action on a thread using the following API, so strange selector poiOneBoxSearch hasn't been invoked, why? Any mistake on the code? Thanks.
- (void)poiOneBoxSearch{
[self poiOneBoxSearcWithQueryString:#"coffee" isFinished:YES];
}
- (void)test1{
NSThread* thread = [[NSThread alloc] init];
[self performSelector:#selector(poiOneBoxSearch)
onThread:thread
withObject:nil
waitUntilDone:YES];
[thread release];
}
If You want use performSelector Method You should Read below Link
,I Think You missed SOmething
Please Goes Through This Link
If Not you may Use Below Code.
Try This
- (void)test1{
[NSThread detachNewThreadSelector:#selector(poiOneBoxSearch) toTarget:self withObject:nil];
}
Try this:
[self performSelectorInBackground:#selector(poiOneBoxSearch) withObject:nil waitUntilDone:YES];
[self performSelectorInBackground:#selector(poiOneBoxSearch) withObject:nil];
- (void) poiOneBoxSearch{
#autoreleasepool {
[self poiOneBoxSearcWithQueryString:#"coffee" isFinished:YES];
} }
The most important thing that you have to keep in mind is that since this method creates a thread on the given selector, the selector must have an autorelease pool just like any other thread in a reference-counted memory environment.
in a method, i want to call a method after n seconds:
self.toolBarState = [NSNumber numberWithInt:1];
[self changeButtonNames];
[self drawMap];
[self performSelector:#selector(showActionSheet) withObject:nil afterDelay:2];
i want to show the action sheet 2 seconds after drawMap is complete. when i use this performSelector, it never makes the call.
if i just put [self showActionSheet];, it works just fine. is there reason why the performSelector is not making the call?
EDIT: in another part of my code, i make the same call and it works:
HUD = [[MBProgressHUD alloc] initWithView:self.view];
[self.view addSubview:HUD];
HUD.delegate = (id) self;
[HUD showWhileExecuting:#selector(drawMap) onTarget:self withObject:nil animated:YES];
[self performSelector:#selector(showActionSheet) withObject:nil afterDelay:6];
here, the showActionSheet gets called 6 seconds after drawMap has completed. i'm guessing there is something going on with the threads that i don't understand yet...
EDIT2:
-(void)showActionSheet
{
InspectAppDelegate *dataCenter = (InspectAppDelegate *) [[UIApplication sharedApplication] delegate];
if (dataCenter.fieldIDToPass == nil)
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Selected Boundary Options" delegate:(id) self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Analyze a Field",#"Retrieve Saved Analysi", #"Geotag Photos", #"Refresh the map",nil];
actionSheet.tag = 0;
[actionSheet showInView:self.view];
}
else
{
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:#"Selected Boundary Options" delegate:(id) self cancelButtonTitle:#"Cancel" destructiveButtonTitle:nil otherButtonTitles:#"Analyze a Field",#"Retrieve Saved Analysi", #"Geotag Photos", #"Attribute the Field", #"Refresh the map",nil];
actionSheet.tag = 0;
[actionSheet showInView:self.view];
}
}
EDIT3:
ok, so the progress of method calls is:
-(void) foundDoubleTap:(UITapGestureRecognizer *) recognizer
{
[HUD showWhileExecuting:#selector(select) onTarget:self withObject:nil animated:YES];
}
-(void) select
{
[self changeButtonNames];
[self drawMap];
[self performSelector:#selector(showActionSheet) withObject:nil afterDelay:2];
}
showActionSheet never gets called. like i said, i'm pretty sure its a threading issue. if call it with [self showActionSheet], it will run. =/
I ran into this same issue, and by necessity I solve it slightly different from the accepted answer. Notice I wanted my delay and selectors to be variables? Using a block allows me to stay within my current method.
dispatch_async(dispatch_get_main_queue(), ^{
[self performSelector:loopSelector withObject:nil afterDelay:cycleTime];
});
By the way, this is definitely a threading issue. The documentation for performSelector:withObject:afterDelay: states that this will be performed on the current thread after the delay, but sometimes that thread's run loop is no longer active.
A more detailed discussion on the subject can be found here
Try using:
-(void) select {
[self changeButtonNames];
[self drawMap];
[self performSelectorOnMainThread:#selector(showActionSheet) withObject:nil waitUntilDone:YES];
}
-performSelector:withObject:afterDelay: schedules a timer on the same thread to call the selector after the passed delay.
Maybe this will work for you:
-(void) select {
[self changeButtonNames];
[self drawMap];
[self performSelectorOnMainThread:#selector(someA) withObject:nil waitUntilDone:YES];
}
-(void)someA {
[self performSelector:#selector(showActionSheet) withObject:nil afterDelay:2];
}
Does your class still exist in memory?
If your class goes away before the performSelector fires, do you wind up sending the message to nil (which would cause nothing to occur).
You could test this by dropping an NSLog into your dealloc()
You mentioned threads. If your performSelector isn't called from the MainThread it could cause issues (UI things should be done on the main thread).
I got the same problem when I call performSelector:withObject:afterDelay: in a background thread created by ReactiveCocoa.
If I execute the block in the ReactiveCocoa's way, the block will be called correctly:
[[[RACSignal empty] delay:2.0] subscribeCompleted:^(){
// do something
}];
I guess there is some magic in the ReactiveCocoa's threading model.
I'm doing an app that loads the contents of viewControllers using NSThread while is reading an XML file.
I have it done as follows:
-(void)viewDidAppear:(BOOL)animated
{
// Some code...
[NSThread detachNewThreadSelector:#selector(loadXML) toTarget:self withObject:nil];
[super viewDidAppear:YES];
}
-(void)loadXML{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Read XML, create objects...
[pool release];
}
My problem is that I don't know how to stop the NSThread if the user changes to another viewController while the NSThread is loading, doing that the app crashes.
I've tried to cancel or exit the NSThread as follows but without success:
-(void)viewsDidDisappear:(BOOL)animated{
[NSThread cancel];
// or [NSThread exit];
[super viewDidDisappear:YES];
}
Can anyone help? Thanks.
When you detach new thread, you can no more cancel or exit it from viewDidDisappear etc. These UI specific methods execute only on main thread so the exit/cancel applies to the main thread which is obviously wrong.
Instead of using the detach new thread method, declare NSThread variable in .h and initialize it using initWithTarget: selector: object: method and cancel it whenever/wherever you want to..
you can also use [NSThread exit]; method of NSThread.
It's better to let a thread end gracefully, i.e. reach its natural conclusion, if you can. It sounds like in your case you can afford to. Also be sure that you're updating the user interface from the main thread, not a secondary thread, as UIKit is not thread safe.
You wrote:
... the app stops responding while the thread finishes...
Once you flag a thread for cancelling or exit, you have to manually stop whatever the thread was called to do. An example:
....
- (void) doCalculation{
/* Do your calculation here */
}
- (void) calculationThreadEntry{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; NSUInteger counter = 0;
while ([[NSThread currentThread] isCancelled] == NO){
[self doCalculation];
counter++;
if (counter >= 1000){ break;
} }
[pool release]; }
application:(UIApplication *)application
- (BOOL)
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
/* Start the thread */
[NSThread detachNewThreadSelector:#selector(calculationThreadEntry)
toTarget:self withObject:nil];
// Override point for customization after application launch. [self.window makeKeyAndVisible];
return YES;
}
In this example, the loop is conditioned on the thread being in a non-cancelled state.
I want to display the view first and then load the data in a background thread. When I navigate from root controller to the view controller, I want to display the view first. As of now, it stays on the root controller until the view controller is loaded. Here's my code for the root controller.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ProductDetailViewController *tempProductDetail = [[ProductDetailViewController alloc] init];
[self.navigationController pushViewController:tempProductDetail animated:YES];
[tempProductDetail release];
}
ProductDetailViewController, here I want to display the view first and then load the data...
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
[self performSelectorOnMainThread:#selector(workerThread) withObject:nil waitUntilDone:NO];
}
-(void) workerThread{
NSAutoreleasePool *arPool = [[NSAutoreleasePool alloc] init];
[arPool release];
}
Don't know what I'm doing wrong. Please, help.
Use [self performSelectorInBackground:#selector(workerThread) withObject:nil]; instead of
[self performSelectorOnMainThread:#selector(workerThread) withObject:nil waitUntilDone:NO];
found the answer for this issue,
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:YES];
[self performSelectorInBackground:#selector(workerThread) withObject:nil];
}
- (void) workerThread
{
// Set up a pool for the background task.
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
// only do data fetching here, in my case from a webservice.
//...
// Always update the components back on the main UI thread.
[self performSelectorOnMainThread:#selector(displayView) withObject:nil waitUntilDone:YES];
[pool release];
}
// Called once the background thread task has finished.
- (void) displayView
{
//here in this method load all the UI components
}
Consider using the following pattern instead for threading, in my opinion it's much cleaner:
- (void)viewWillAppear:(BOOL)animated
{
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self
selector:#selector(someFunction)
object:nil];
[[NSOperationQueue currentQueue] addObject:operation]; // this will actually start the thread
[operation release];
}
- (void)someFunction
{
// don't need to initialize and release an autorelease pool here,
// you can just write a function as usual ...
[self updateUI];
}
- (void)updateUI
{
if (![NSThread isMainThread]) // if we need a UI update, force it on main thread
{
[self performSelectorOnMainThread:#selector(updateUI) withObject:nil waitUntilDone:YES];
return;
}
// do UI updates here
}
By writing code in this way, you can more dynamically decide which function you want to thread, since there is no autorelease pool requirement. If you need to do UI updates, the updateUI function will make sure for itself that it's running on the main thread, so the caller doesn't need to take this into account.
I am checking network reachability in applicationDidFinishLaunching:
[self performSelectorInBackground:#selector(performReachabilityCheck) withObject:nil];
Background thread
-(void)performReachabilityCheck{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
internetReach = [[Reachability reachabilityForInternetConnection] retain];
[internetReach startNotifer];
[self updateInterfaceWithReachability: internetReach];
[pool release]; pool = nil;
}
I'm not sure why my app fails to launch in time?
Is [self updateInterfaceWithReachability: internetReach]; correctly updating the UI in the main thread? If not, that could be a problem.
Otherwise, I would suggest you make sure that your applicationDidFinishLaunching: is correctly returning quickly as you expect.
Another thing to try is to break into the debugger as the app is firing up but before it has failed to launch. Check the backtrace and make sure the main event loop is in a sensible state (as it sounds like it isn't).