Sleep or Pause NSThread - ipad

I am creating a new Thread which runs one of my method after every certain period of time.
Now what i am doing is as follows:
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:#selector(setUpTimerThread) object:nil];
[thread start];
the above method calls my setUpTimerThraed method, and this method makes an NSTimer and calls a specific method i.e syncData after every 1 minute. Now what i want is my sync Data method is sending some files to the FTP folder. and when ever it send one file to the FTP I want it my "thread" to be sleep for a while.
i have used
[NSThread sleepForTimeInterval:3.0];
But this code blocks my application main thread. Is there any way i can only sleep my "thread" thread for a while so that it wont stop my application responding for 3 seconds and does not sleep my main thread.
Hope u get what i am asking guys. PLease help?

sleepForTimeInterval: sleeps the thread that it is called on. Try calling a sleep on the thread you want to sleep rather than the main thread.
replace your current sleep call with
[self performSelector:#selector(sleepThread) onThread:thread withObject:nil waitUntilDone:YES];
then implement this method
-(void)sleepThread {
[NSThread sleepForTimeInterval:3.0];
}

The solution of ColdLogic is right, but it's neccesary put the flag waitUntilDone to YES, otherwise the method is never called.

Related

performSelectorWithDelay in serialQueue

I've a serial queue and I use that queue to call a performSelectorWithDelay like below
dispatch_async(serialQueue, ^(void) {
[self performSelector:#selector(fetchConfigFromNetwork) withObject:nil afterDelay:rootConfig.waitTime];
});
However, the method fetchConfigFromNetwork never gets called. However, if instead of serialQueue, I use mainQueue - it starts working.
Cannot understand what's happening here and how to fix it?
The explanation why your code doesn't work is in the documentation: https://developer.apple.com/documentation/objectivec/nsobject/1416176-performselector?language=occ
This method registers with the runloop of its current context, and
depends on that runloop being run on a regular basis to perform
correctly. One common context where you might call this method and end
up registering with a runloop that is not automatically run on a
regular basis is when being invoked by a dispatch queue. If you need
this type of functionality when running on a dispatch queue, you
should use dispatch_after and related methods to get the behavior you
want.
I'm assuming you want that method to be called on the serial queue with a delay. The most straight forward (and recommended way) is to use dispatch_after:
__weak typeof(self) wself = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(rootConfig.waitTime * NSEC_PER_SEC)), serialQueue, ^{
[wself fetchConfigFromNetwork];
});
This method sets up a timer to perform the aSelector message on the current thread’s run loop. The timer is configured to run in the default mode (NSDefaultRunLoopMode). When the timer fires, the thread attempts to dequeue the message from the run loop and perform the selector. It succeeds if the run loop is running and in the default mode; otherwise, the timer waits until the run loop is in the default mode.
This is the discussion about the method performSelector:withObject:afterDelay:, I think the block of dispatch_async will execute on a new thread (not main thread), but you would not know which thread it is, so you can not new a runloop and open it and assign it to this thread. because the runloop of thread is close in default except the main thread, the timer will wait forever.
On my opinion, you should use NSThread instead of dispatch_async, and create a runloop for the thread that you use, then specified the mode of runloop with NSDefaultRunLoopMode, if you actually want to cancelPreviousPerformRequestsWithTarget, otherwise use dispatch_after instead of performSelector.
That's my understanding. I can't promise it is right.

iOS, how to restart NSThread?

To restart the NSSthread, I'm using the code below:
- (IBAction)listen:(id)sender {
thread = [[NSThread alloc] initWithTarget:self selector:#selector(listen1) object:nil];
[thread start];
[thread cancel];
[thread start];
}
But when I built and pressed this button, I've received error: "attempt to start the thread again"
Can you help me?
Method -cancel doesn't stop the thread, it just sets cancel flag.
Changes the cancelled state of the receiver to indicate that it should exit.
- (void)cancel
The semantics of this method are the same as those used for the NSOperation object. This method sets state information in the receiver that is then reflected by the isCancelled method. Threads that support cancellation should periodically call the isCancelled method to determine if the thread has in fact been cancelled, and exit if it has been.
You can stop a Thread only from within itself by calling [NSThread exit].
By the way, what are you trying to achieve? Starting separate thread is almost never good idea and starting the same thread twice is twice wrong.

NSTimer as background thread

I need to ping a server at fixed intervals. I am currently using the following:
[NSTimer scheduledTimerWithTimeInterval:5.0f
target:[Socket getInstance]
selector:#selector(sendHeartBeats)
userInfo:nil
repeats:YES];
This calls function sendHeartBeats at an interval of 5 sec.
Do i need to call this on a separate thread so that my main thread will not be affected?
NSTimers, as well as the related NSRunLoop, do not affect (nor are aware of) the threading behavior of your process. Both just use the current thread.
This means that you have to care about threads on your own. NSTimer, in conjunction with NSRunLoop give you the opportunity to schedule timed tasks on a given thread.
You can use a timer on the main thread or start a new thread, add a runloop to it and start a timer on that background thread.
Anyway, when using threads, you have to be aware of thread safety issues. In this case this means making the Socket class (singleton?) thread safe because it is probably used elsewhere in your app.
Well to answer the question, the answer is "no" you don't need a background thread in order to avoid disrupting the main thread with a timer.
At least that's true of the NSTimer mechanism, however if the method that is called by the timer spends a lot of time doing something then the answer would "yes", you should call it in a background thread. However you are required to provide a runloop in that background thread in order for NSTimer to work, and then it gets complicated.
Therefore if I was going to do something in a background thread I would avoid NSTimer and simply do something like:
while (YES) {
[[NSThread currentThread] sleepForTimeInterval:5.0];
if ([[NSThread currentThread] isCancelled])
break;
doThing();
}
The thread that started this background thread would then call [thread cancel] in order to cancel that thread.
Do i need to call this on a separate thread so that my main thread
will not be affected?
No need.
Timers work in conjunction with run loops. To use a timer effectively, you should be aware of how run loops operate—see NSRunLoop and Threading Programming Guide.

dispatch_async block on main queue is never execeuted

I have an app that uses a connection queue that handles the connections on a background thread. Each connection sends a JSON post, then when it receives a success, saves some objects into coredata.
Once all connections are complete, i call a dispatch_async on the main thread to call a finished method.
However, under very specific conditions of data im sending/saving, I've noticed the dispatch_async block to the main thread never gets called, and the app screen freezes, all execution stops, and the app sits idle with a frozen screen. processing power according to xcode is 0%.
Here is method with the block that fails.
- (void)connectionDidComplete
{
_completeConnections++;
_syncProgress = (float)_completeConnections / (float)_totalConnections;
dispatch_async(mainQueue, ^(void) {
[[NSNotificationCenter defaultCenter] postNotificationName:SyncQueueDidUpdateNotification object:nil];
}); <-- this dispatch works
if (_completeConnections == _totalConnections)
{
// clear unsynced data
NSArray *syncedObjects = [SyncObject completedSyncObjects];
if (syncedObjects.count > 0)
{
for (SyncObject *syncObject in syncedObjects)
{
[syncObject delete];
}
}
//this method saves the current context, then merges this context with the main context right after
[[VS_CoreDataManager sharedManager] saveManagedObjectContextAndWait:managedObjectContext];
// cleanup the thread's context
[[VS_CoreDataManager sharedManager] unRegisterManagedObjectContextForThread:currentThread];
managedObjectContext = nil;
// complete sync
dispatch_async(mainQueue, ^(void) {
[self performSelector:#selector(finishSync) withObject:nil afterDelay:2];
}); <-- this dispatch never gets called
}
}
My suspicion is this problem has something to do with saving the context then merging it. And possibly while that is happening its released in the middle of the merge, causing some weird hang up and the dispatch isn't getting executed. This is just a guess though, and I don't know how to fix it.
Any ideas?
Thanks.
If the block on the main thread is not executed, then it is because of 1 of 2 reasons.
The main thread is blocked; is not processing any events at all. Got a while() loop on the main thread? That'd do it. A lock? There you go.
The main thread is running a modal run loop inside the outer run loop. Asynchronous dispatches to the main event loop -- main thread -- won't be processed in this case.
Set a breakpoint on that dispatch_async() and see what the main thread is doing (at the point of dispatch the main thread is most likely already in the bad state).
DarkDust's suggestion of using dispatch_after() is a good one, but is unlikely to work in that it is almost assuredly the case that your main thread is not processing events when the problem occurs. I.e. fix the problem, then move to dispatch_after() as DarkDust suggests.
If your main thread is busy with modal runloop, then you could try
CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, block
});
I believe this is a great discussion. I came across this when I had the following code:
dispatch_synch(dispatch_get_main_queue()){
print("I am here")
}
the print code did not execute as I was dispatching a 'synch' block on the serial main thread which caused a dead lock. print was waiting for the dispatch to finish and dispatch was waiting for print to finish. When you dispatch in the main serial queue then you should use dispatch_async. and i guess if you use a concurrent queue then dispatch synch suits better

How can we stop thread

I am developing application in which my thread is starting when connectionDidFinishLoading.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[downloadingthread cancel];
downloadingthread = [[NSThread alloc]initWithTarget:self selector:#selector(startusingthread) object:nil];
[downloadingthread start];
}
connectionDidFinishLoading is called multiple times, so I want to stop download thread and then start agin it again. I am trying to execute last thread only. Please help me to stop my thread in between.
Never stop a thread by force.
You stop the request using -[NSURLConnection cancel].
Your thread should be on a run loop, so you would cancel the run loop for that thread if you are aborting the request but... it's very expensive to create threads all over the place, and there is often a better alternative to this problem.

Resources