I am using the thread to call my function "initialGetMethod"
[NSThread detachNewThreadSelector:#selector(initialGetMethod) toTarget:self withObject:nil];
and my get method is
-(void) initialGetMethod
{
self.loginPassword = [[ UIAlertView alloc] initWithTitle:#"Please Login to MFP" message:#"Enter Valid UserID and Password" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:#"Cancel", nil];
[self.loginPassword setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];
[self.loginPassword setTag:2];
[self.loginPassword show];
}
but its giving the exception "Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. "
its giving the exception at "[self.loginPassword setAlertViewStyle:UIAlertViewStyleLoginAndPasswordInput];"
and if i call the function as "[self initialGetMethod];" its not giving the exception but it will take some time..
i tried loading in background but its not working.. (mean i dont want it to be in background)..
please suggest some solution ..
The error which you are getting during running application is
"Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. "
which is occur once you are updating or accessing the UI elements in any other thread except the MainThread (Use Main thread only to access or Update the UI it will only help you)
Here you are showing Alert in Background thread that's why it happens
Please use one of the following to PopUp alert
[self performSelector:#selector(initialGetMethod) withObject:nil];
[self performSelector:#selector(initialGetMethod) withObject:nil afterDelay:0.1];
//call createthread:
[self setupTimerThread:];
//write following code in setupTimerThread
timer = [NSTimer timerWithTimeInterval:02
target:self
selector:#selector(initialGetMethod:)
userInfo:nil
repeats:NO];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addTimer:timer forMode:NSRunLoopCommonModes];
[runLoop run];
Related
I am trying to timeout my NSOperation with a NSTimer but my timer is not getting fired. Please see below the code I have written inside my class which is sub classing NSOperation.
- (void)start {
// Start the timer for Time out before the ping activity starts
self.timeOutTriggerTimmer = [NSTimer scheduledTimerWithTimeInterval:10.0 target:self selector:#selector(cancelTheOperation) userInfo:nil repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:self.timeOutTriggerTimmer forMode:NSDefaultRunLoopMode];
// Check for cancellation
if ([self isCancelled]) {
[self completeOperation];
return;
}
// Executing
[self willChangeValueForKey:#"isExecuting"];
executing = YES;
[self didChangeValueForKey:#"isExecuting"];
// Begin
[self beginOperation];
}
It's easiest to just add the timer to the main run loop, not the current run loop:
[[NSRunLoop mainRunLoop] addTimer:self.timeOutTriggerTimmer forMode:NSDefaultRunLoopMode];
Alternatively, you can keep your timer as it is (scheduled on the current run loop), but then you have to keep the runloop alive, perhaps adding something like the following to the end of the start method (note, Apple recommends this rather than the run method):
while ([self isExecuting] && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]);
But this (like the run method you contemplated) effectively keep the start method running until execution is done (making what appears to be a concurrent operation to behave more like a non-concurrent operation).
I suspect you're doing this already, but just in case, make sure to invalidate your timer when you complete your operation, or else the timer will retain the operation until the timer fires, unnecessarily delaying the freeing of the operation's resources (and calling the cancelTheOperation even though the operation may well already be done).
I found the issue. I need to put the below statement to have it executed.
[[NSRunLoop currentRunLoop] run];
Im writing a little command line tool that use AFHTTPNetworkng to pull some data from a server and display it. However because AFHTTPNetwotking uses an asynchronous call back, the application exits prior to getting the response from the server. I there for added
NSRunLoop *run = [NSRunLoop currentRunLoop];
_timer = [NSTimer timerWithTimeInterval:0.5 target:self selector:#selector(check) userInfo:nil repeats:YES];
[run addTimer:_timer forMode:NSDefaultRunLoopMode];
[run runUntilDate:[NSDate distantFuture]];
this timer calls a check method that checks to see if a BOOL has been set to yes (This happens in the call back). If it has it invalidates the timer.
- (void)check{
NSLog(#"checking");
if (test == YES) {
[_timer invalidate];
}
return;
}
This code works fine but now the app does not terminate, suggesting that the runloop is still running. I could use exit() to kill the app but this does not seem acceptable as this may cause a memory leak.
I have a table that is refreshing itself every two seconds. It works great on the simulator and on my wifi. But once I switch to the cellular network (or any slow network), I cannot select the rows reliably.
Sometimes when I click a row it will work after 8 seconds. Sometimes never.
I thought my refresh function was causing the delay but I printed the time at the beginning and end of the function and it only takes 2 milliseconds.
Has anyone had a similar slow network issue? Any tips on what might be the cause of the hang-up?
My refresh function is called in viewDidLoad:
//Set timer to call refresh function every two seconds
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:#selector(updateMethod) userInfo:nil repeats:YES];
My updateMethod is:
- (void) updateMethod
{
[columnArray removeAllObjects];
[self getColumnData];
[homeTable reloadData];
}
getColumnData calls a website and puts data in the columnArray
You must not perform network operations on the main queue. You can create an NSOperationQueue to move the network logic to a background queue and only perform the UI update in the main queue when the network operation ends.
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.name = #"Data request queue";
[queue addOperationWithBlock:^{
[self getColumnData];
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[homeTable reloadData];
}];
}];
I have a function drawView which is thread safe and does drawing for short periods of game animation. I have functions startAnimating and stopAnimating. I want a background thread to call drawView at a regular rate but only during the period that the animation is enabled.
In startAnimating I was going to call the view's performSelectorInBackground:withObject: to get the thread running.
I'm a little confused about how to do the thread communication and initialize the drawing thread: specifically, setting up a runloop to receive display link messages and then at the end notifying the thread that it should exit and exiting the run loop cleanly when stopAnimating is called from the main thread. I want to ensure that drawView is never called after stopAnimating, and also that the drawing thread is not cancelled abruptly in the middle of the drawing operation. I have seen a lot of very poor answers to this kind of question on line.
OK after reading the Apple pages all evening, I finally solved it with this code:
// object members
NSThread *m_animationthread;
BOOL m_animationthreadrunning;
- (void)startAnimating
{
//called from UI thread
DEBUG_LOG(#"creating animation thread");
m_animationthread = [[NSThread alloc] initWithTarget:self selector:#selector(animationThread:) object:nil];
[m_animationthread start];
}
- (void)stopAnimating
{
// called from UI thread
DEBUG_LOG(#"quitting animationthread");
[self performSelector:#selector(quitAnimationThread) onThread:m_animationthread withObject:nil waitUntilDone:NO];
// wait until thread actually exits
while(![m_animationthread isFinished])
[NSThread sleepForTimeInterval:0.01];
DEBUG_LOG(#"thread exited");
[m_animationthread release];
m_animationthread = nil;
}
- (void)animationThread:(id)object
{
#autoreleasepool
{
DEBUG_LOG(#"animation thread started");
m_animationthreadrunning = YES;
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
CADisplayLink *displaylink = [CADisplayLink displayLinkWithTarget:self selector:#selector(displayLinkAction:)];
[displaylink setFrameInterval:3];
[displaylink addToRunLoop:runLoop forMode:NSDefaultRunLoopMode];
while(m_animationthreadrunning)
{
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
DEBUG_LOG(#"runloop gap");
}
[displaylink removeFromRunLoop:runLoop forMode:NSDefaultRunLoopMode];
DEBUG_LOG(#"animation thread quit");
}
}
- (void)quitAnimationThread
{
DEBUG_LOG(#"quitanimationthread called");
m_animationthreadrunning = NO;
}
- (void)displayLinkAction:(CADisplayLink *)sender
{
DEBUG_LOG(#"display link called");
//[self drawView];
}
The reason I use the line [self performSelector:#selector(quitAnimationThread) onThread:m_animationthread withObject:nil waitUntilDone:NO] and not simply set m_animationthreadrunning = NO in stopAnimating is because the run loop may not return in a timely fashion, but calling a selector forces it to return.
I have to perform a timer using a NSThread as I need to download text data from the web, and without that, in 3G connection it freezes the UI while downloading. So I've used a NSThread but it still freezes for a while and I don't know how to solve this....
Here's the code I'm using to perform the timer:
- (void)viewDidLoad{
[NSThread detachNewThreadSelector:#selector(onTimerK2) toTarget:self withObject:nil];
}
- (void)onTimerK2{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
timer = [NSTimer scheduledTimerWithTimeInterval:15 target:self selector:#selector(onTimerKY2) userInfo:nil repeats:YES];
[pool release];
}
- (void)onTimerKY2{
NSLog(#"working");
}
You're detaching a new thread to call onTimerK2, which then immediately calls a method back on the main thread, which will of course freeze your interface.
Edit
You should be doing any long-running work not on the main thread (either yourself, or by using the asynchronous nature of NSURLConnection as mentioned elsewhere),and then updating your UI by calling selectors on the main thread as this activity progresses.
Having said that, you may have more success with the following changes/reordering of your code:
- (void)viewDidLoad {
timer = [NSTimer scheduledTimerWithTimeInterval:15
target:self
selector:#selector(onTimerK2)
userInfo:nil
repeats:YES];
}
- (void)onTimerK2{
[NSThread detachNewThreadSelector:#selector(onTimerKY2)
toTarget:self
withObject:nil];
}
- (void)onTimerKY2{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(#"working");
[pool release];
}
It's not very clear how you are trying to solve the UI freeze problem by using timer. But if your UI is freezing due to downloading then you can try asynchronous loading instead of using timer or detaching another thread.
EDIT: Unless you configure a run loop for secondary thread, timer is not going to work from that thread. Check the run loop management in threading programming guide. This can be a far difficult work than to use asynchronous connection.