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).
Related
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 ....
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've this bit of code:
- (IBAction)registerAction:(id)sender {
[NSThread detachNewThreadSelector:#selector(registerThread) toTarget:self withObject:nil];
}
- (void)registerThread {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyDelegate *delegate = (MyDelegate *)[[UIApplication sharedApplication] delegate];
NSInteger locationID = [delegate.api checkCoordinate:[NSString stringWithFormat:#"%f,%f",
location.coordinate.latitude, location.coordinate.longitude]];
NSNumber *status = [api registerWithUsername:usernameField.text
password:passwordField.text email:emailField.text andLocation:locationID];
[self performSelectorOnMainThread:#selector(registrationDoneWithStatus:) withObject:[NSNumber numberWithInt:1] waitUntilDone:NO];
[pool release];
}
it works nicely, but sometimes I get this error:
void _WebThreadLockFromAnyThread(bool), 0x6157e30: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
And it seems that only using the delegate I get this error, and I don't know how to resolve.
Thanks in advance :)
I've run into the same problem recently.
There may be some active views (eg. UITextField,UITextView). Try resignFirstResponder those views before accessing delegate
You fix the problem by very carefully thinking through your application's concurrency architecture and ensuring that you aren't exercising anything from a thread that should only be done on the main thread.
In this case, you are causing the UIKit to execute code from a secondary thread. If you were to set a breakpoint on _WebThreadLockFromAnyThread, you would know exactly where.
It is exceedingly atypical to use the app's delegate from a secondary thread in anything but the most extremely controlled circumstances.
tl;dr You can't make an app threaded by detaching a new thread against a random selector.
I have an app that I am refactoring and I just implemented multithreading so that the UI may run smoother. In the iphone simulator I don't get any leaks but testing on my iPhone 3G running on iOS 4.2 I get a memory leak. I have done a lot of searching for the correct way to implement an autoreleasepool with an operationqueue, help will be greatly appreciated.
I have created an nsoperationqueue in my viewcontroller as such
- (void)loadData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSOperationQueue *queue = [NSOperationQueue new]; // creates multithread for loading data without slowing UI
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(firstRun) object:nil];
[queue addOperation:operation];
[operation release];
[queue release];
[pool release];
}
First, you shouldn't just create and then release the queue. It's more natural to create that queue as one of your class's ivars and then release it when your view controller goes away (you can also cancel up any pending operations and cancel/wait for any running operations to complete).
Second, you don't need the autorelease pool in the method that creates the operation and adds it in the queue since that method is being called from the main thread. Instead, you need the autorelease pool from the method your object actually calls (this is what may be running on another thread).
So, you might have the following (assuming you name your queue ivar queue_):
- (void)viewDidLoad
{
[super viewDidLoad];
if( !queue_ ) queue_ = [[NSOperationQueue alloc] init];
// other view loading code
}
- (void)loadData
{
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:#selector(firstRun) object:nil];
[queue_ addOperation:operation];
[operation release];
}
- (void)firstRun
{
// Here we may run on another thread, so 1) we need an autorelease pool; and
// 2) we need to make sure we don't do anything that requires a runloop
NSAutoreleasePool* threadPool = [NSAutoreleasePool new];
// do long-running things
[threadPool drain];
}
- (void)dealloc
{
if( queue_ ) {
[queue_ setSuspended:YES];
[queue_ cancelAllOperations];
// you need to decide if you need to handle running operations
// reasonably, but don't wait here because that may block the
// main thread
[queue_ release];
}
// other dealloc stuff
[super dealloc];
}
You could also initialize your queue on demand, so instead of initializing in viewDidLoad, check for its existence and initialize if necessary anywhere you'd add an operation. This might be wrapped in a method call of its own, but lazy initialization here probably isn't really necessary as queues are pretty light-weight.
You should create an NSAutoreleasePool at the start of the method that the NSOperation will invoke (in this case, firstRun), and drain it at the end of the method.
In my iPhone app I need to connect to a web server as this can take some time I'm using threads like this:
[NSThread detachNewThreadSelector:#selector(sendStuff) toTarget:self withObject:nil];
- (void)sendStuff {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Need to get the string from the textField to send to server
NSString *myString = self.textField.text;
//Do some stuff here, connect to web server etc..
[pool release];
}
On the row where I use self.textField I get a warning in console saying:
void _WebThreadLockFromAnyThread(bool), 0x5d306b0: Obtaining the web lock from a thread other than the main thread or the web thread. UIKit should not be called from a secondary thread.
How can I use the textField without getting this error?
It depends a little bit on what you want to do with the textField. If reading the value is the only thing, you can do:
[NSThread detachNewThreadSelector:#selector(sendStuff) toTarget:self withObject:self.textField.text];
- (void)sendStuff:(NSString*)myString {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Do someting with myString
[pool release];
}
If you want to change a value on the textField you could:
[self.textField performSelectorOnMainThread:#selector(setText:) withObject:#"new Text"];
Perform any selectors that handle UI updates on the main thread. You can do this with the NSObject method -performSelectorOnMainThread:withObject:waitUntilDone:
Why not:
[NSThread detachNewThreadSelector: #selector(sendStuff:) toTarget: self withObject: self.textField.text];
?
This is indeed unsafe behaviour. The MainThread is the only one that should interface the UI. Have your thread return for instance a string to the mainthread and have a method there update the UI. You can do for instance do this by passing a selector to the other thread method, and then have the other thread call the selector on the mainthread.
[self performSelectorOnMainThread:#selector(myMethod) withObject:nil waitUntilDone:NO];
will work