NSTimer in a for loop - objective-c

I want to call the getData method after waiting 2 seconds each time this loop...loops. I've written out the NSTimer a number of times inside and outside the loop but can't get the correct usage for it to do what I want.
for (TwitterPerson *person in [tempDict allValues]) {
[self getDataFromTwitterUserAPIandArchiveFor:person.handle];
}

Could you set it up differently and call the [getData... method every time the timer fires? You could keep your dictionary keys in an array and pop the next key each time the timer fired.
I think the NSTimer is designed to not block the main thread whereas the for-loop definitely blocks the thread.
As in this related question Using NSTimer in a Loop, you might consider NSRunLoop.

Related

How to make sure my timer run is race free

This is not the actual code, only to provide the idea behind the logic in actual code. Do I need a Mutex, mylock2 ,inside the timer function?. The timer runs every 0.02 seconds. Or, the timers are safe in that regard?.
Static NSTimer *mylock1 = nil; //initialized and used for another purpose
Static NSTimer *mylock2 = nil //initialized and used for the timer
- (void)timerFireMethod:(NSTimer*)theTimer
{
[mylock2 lock];
Self.Mycount = 0;
for (int j = 0; j <n; j++)
{
if (b) NSLog(#”Hi”);
else Self.Mycount = Self.Mycount + 1;
}
If (Self.Mycount == n)
[self stopMytimer];
[mylock2 unlock];
}
You might be misunderstanding how NSTimer works.
NSTimer invocation is handled by a run loop, when a timer is scheduled it is attached to the current run loop. A run loop is, unsurprisingly, a loop and runs on a single thread. Each iteration of the run loop a check is made if any timer needs to be fired, and if so it is called and so the next operation the run loop will do cannot occur until that call returns...
the timer uses scheduledTimerWithTimeInterval. if the timer gets fired every 0.02 sec, how to void overlapping timer calls?
Under normal circumstances calls simply cannot overlap as the next one cannot occur until the current one returns.
Of course if you dispatch work asynchronously to another thread within your timer, start another run loop from within the timer and schedule the timer on that one as well, or any other creative way you come up with then it is possible to create the conditions for "overlapping" calls. Your timerFireMethod: is doing nothing like that and will simply be called, execute, and return.
does "Self.Mycount" become 0 in middle of the for loop execution causing unexpected behaviors?
Probably – as your method isn't designed for that scenario. But unless you fire up another thread (using NSThread, GCD (dispatch), etc.), and have it set Mycount to zero its not going to happen.
HTH

objective-c How to prevent an action while a thread is being executed

I've been using Multithreading for a while I thought I got it but my program is crashing now.
I have a method that has to download data for the server and access memory depending on the data, that process takes long, so I execute it from a secondary thread like this:
-(void)showPeople{
dispatch_queue_t pintaOcupantes = dispatch_queue_create("Pinta Ocupantes", NULL);
dispatch_async(pintaOcupantes, ^{
//BUNCH OF CODE
[self isPersonIn:jid];
//MORE CODE that include methods calling isPersonIn
});
Inside that block there's isPersonIn. It crashes if I press too fast the button that executes showPeople. IsPersonIn is something like:
-(int)isPersonIn:(XMPPJID *)jid{
int i = 0;
for(NSDictionary *card in self.listaGente){
NSLog(#"la jid es: %#", [card objectForKey:#"jid"]);
NSLog(#"la jid del usuario es: %#", jid.user);
if([[card objectForKey:#"jid"] isEqualToString:jid.user]){
return i;
}
i++;
}
return -1;
}
It compares a XMPPJID with an array which is a instance variable.
isPersonIn is called several times from different methods but all the methods that call it belong to the block, so as I understand it, all the executions of isPersonIn should be serialized, FIFO, right?
But if I press the button that executes showPeople, the one containing the block, many times very fast the app crashes on isPersonIn, sometimes without any message. I can see the threads when it crashes and I see at least 2 threads with isPersonIn last in the stack, which doesn`t make sense, since the block should be executed one at a time, not several threads at the same time, right?
Any help will be very much appreaciated.
Thanks!
[EDIT]
Also the instance array, self.listaGente, is modified outside the block.
I'm not a GCD expert, but I suspect the reason you're getting multiple threads is that you're creating a new dispatch queue each time showPeople is called.
So rather than having a single serial queue with multiple blocks, I think you are ending up with multiple queues each executing a single block.
[EDIT] If the collection is modified outside of the block but during execution of the block, this could be the source of your crash. From Fast Enumeration Documentation:
Enumeration is “safe”—the enumerator has a mutation guard so that if you attempt to modify the collection during enumeration, an exception is raised.
In this case protecting the array, that was provoking my app to crash, fixed the problem.
using:
#syncronized(theArray){
//CODE THAT WILL ACCESS OR WRITE IN THE ARRAY
}
This way threads will stop before if there's a thread already executing that code, like a mutex or semaphore

How to get hold of the currently executing NSOperation?

Is there an equivalent to [NSOperationQueue currentQueue] or [NSThread currentThread] for NSOperation?
I have a fairly complex domain model where the heavy processing happens quite deep down in the call stack. In order to timely cancel an operation I would need to pass the NSOperation as a parameter to every method until I get to the point where I want to interrupt a longer running loop. Using threads I could use [[NSThread currentThread] isCancelled] so it would seem convenient if there is an equivalent for NSOperation, unfortunately there is only the seemingly useless [NSOperationQueue currentQueue].
Came up with an extension in swift that returns the running operations
extension NSOperationQueue {
public var runningOperations: [NSOperation] {
return operations.filter {$0.executing && !$0.finished && !$0.cancelled}
}
}
You can then pick up the first one
if let operation = aQueue.runningOperations.first {}
No, there's no method to find the currently executing operation.
Two ways to solve your problem:
Operations are objects. If you need object A to talk to object B, you'll need to arrange for A to have a reference to B. There are lots of ways to do that. One way is to pass the operation along to each object that needs to know about it. Another is to use delegation. A third is to make the operation part of some larger "context" that's passed along to each method or function. If you find that you need to pass a reference from one object through several others just to get it to the object that will finally use it, that's a clue that you should think about rearranging your code.
Have the "heavy lifting" method return some value that gets passed up the call chain. You don't necessarily need the heavy lifting method to call [currentOperation cancel] to accomplish your goal. In fact, it would be better to have it return some value that the operation will understand to mean "work is done, stop now" because it can check that return value and exit immediately rather than having to call -isCancelled once in a while to find out whether it has been cancelled.
This isn't a good idea. Operations are usually canceled by their queue. Within the operation's main() method, you can periodically check if self is cancelled (say, every n trips through a loop, or at the start of every major block of commands) and abort if so.
To respond to a cancellation (say, some UI element tied to the operation's or queue's status), you use key value observing (KVO) to have your controller observe the operations' started, completion, and cancelled properties (as needed), then set your UI's state (always on the main thread) when those keys are updated. Per JeremyP's comments, it's important to note the KVO notifications come from the op's thread and UI should (almost) always be manipulated on the main thread, so you'll need to use -performSelectorOnMainThread... methods to update your actual UI when you receive a state change KVO note about your operations.
What are you really trying to do? That is, why do you feel other parts of your app need to know directly about the current operation?
You could store the current operation in the thread dictionary. Just remember to get rid of it before you exit. You can safely use the thread dict if you created the object.
You can use a combination of [NSOperationQueue currentQueue] & [NSThread currentThread] to accomplish this.
Essentially, you need to loop through the operations on the currentQueue and find the operation running on the currentThread.
NSOperation doesn't provide access to the thread it is running on, so you need to add that property yourself and assign it.
You're probably already subclassing NSOperation and providing a main, so add a 'thread' property to that subclass:
#interface MyOperation : NSOperation
#property(nonatomic,strong) NSThread *thread ;
#end
Then, in your 'main' assign the current thread to that property
myOperation.thread = [NSThread currentThread]
You can then add a 'currentOperation' method:
+(MyOperation *)currentOperation
{
NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ;
NSThread *currentThread = [NSThread currentThread] ;
for( MyOperation *op in opQueue.operations ) {
if( [op isExecuting] && [op respondsToSelector:#selector(thread)] ) {
if( op.thread == currentThread ) {
return ( op ) ;
}
}
}
}
return nil ;
}
How do you know which operation you want to cancel?
When you get to the point that you want to cancel, just call [myQueue operations] and go through the operations until you find ones that you now want to cancel. I guess if you have millions of operations (or thousands) this might not work.
[myQueue operations] is thread safe - a snapshot of the Queue contents. You can dive through it pretty quick cancelling at will.
Another way:
NSOperationQueue is not a singleton, so you can create a Q that has say 200 jobs on it, and then cancel all 20 by just getting that Q and cancelling them all. Store the Q's in a dictionary on the main thread, and then you can get the jobs you want canceled from the dict and cancel them all. i.e. you have 1000 kinds of operations and at the point in the code where you realize you don't need a certain task, you just get the Q for that kind, and look through it for jobs to cancel.

PerformSelector not working

MyThreadRun method is invoked from MyMethod like this
NSArray* args = [NSArray arrayWithObjects:arg1, target, NSStringFromSelector(mySelector), nil];
NSThread* mythread= [[[NSThread alloc] initWithTarget:self selector: #selector(MyThreadRun:) object:args] autorelease];
[MyThreadRun start];
In the end of MyThreadRun, I try to invoke a function in the class which has called MyMethod to initiate the thread to begin with, like this:
NSObject* callbackTarget = [args objectAtIndex:1];
NSString* selector = [args objectAtIndex:2];
[callbackTarget performSelector:NSSelectorFromString(selector) withObject:calculationResult afterDelay:0];
I have a break point on the method that selector is pointing at, and it is never hit.
If I hard code the method name, like this
[callbackTarget updateWithResult:calculationResult]
it works fine.
What is there I need to know about performSelector?
The context where performSelector:withObject:afterDelay: is getting invoked is the culprit. Here's what's going on.
Some members of the performSelector... family, like this one, don't perform the selector right away; they queue up an invocation on the current run loop, so that it happens after your fn returns, the next go-round of the run loop. According to apple: "Specifying a delay of 0 does not necessarily cause the selector to be performed immediately. The selector is still queued on the thread’s run loop and performed as soon as possible."
Normally this is fine and expected. But your code is calling it on a thread that you started manually... and such threads don't keep their run loop going repeatedly the way the main thread does. They invoke the selector specified at creation once, and exit. So: your code queues up an invocation of your callback selector, but then the thread exits; and its run loop is thrown away without ever running... so your queued invocation never happens.
What you probably need is performSelectorOnMainThread:withObject:waitUntilDone:, since you may want the callback to happen on the thread that invoked the MyMethod method in the first place, which is presumably the main thread.
More generally, threading is very tricky stuff. I highly recommend checking out NSOperationQueue, NSBlockOperation, and related techniques - they can remove a great deal of the pain.
Is
NSString* selector = [args objectAtIndex:2];
equal to updateWithResult or updateWithResult:?
They're two different methods. You want the one with the colon.
Remove the "afterDelay:0" and your code works. Also "[MyThreadRun start]" should be "[mythread start]".

NSString alloc or not!

I am running this code from the scrollViewDidScroll method (so it runs when you scroll!):
NSString *yearCount = [[NSString alloc] initWithFormat:#"%0.1f", theScroller.contentOffset.y];
years.text = yearCount;
[yearCount release];
which works fine, however it hits performance on the scroll (causing it to judder as it slows down)
My question is, do I need to keep using alloc and release or is there a way to get some numbers using initWithFormat onto some text without it?
years.text = [NSString stringWithFormat:#"%0.1f", theScroller.contentOffset.y];
will avoid the need to explicitly release the string, since it is autoreleased.
However, if you are trying to avoid slowdown, consider updating the field less frequently. For example, each time scrollViewDidScroll is called, set a timer to update the field in say 0.1 seconds from now, but not if the timer is already running from a previous call. This reduces the number of calls while keeping the UI updated.
Here is an example how you could do it. Declare an NSTimer in the interface declaration of your scroll view delegate:
NSTimer *timer;
And methods:
- (void)updateYear:(NSTimer*)theTimer
{
timer=nil;
UIScrollView *theScroller=[theTimer userInfo];
years.text=[NSString stringWithFormat:#"%0.1f", theScroller.contentOffset.y];
}
- (void)scrollViewDidScroll:(UIScrollView *)theScroller
{
if (!timer) {
timer=[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(updateYear:) userInfo:theScroller repeats:NO];
}
}
Obviously, you don't have to use 0.1 as the time interval, you can try making it faster or slower and see what works best.
Note that this example is complete as far as memory management is concerned, You should not try to retain or release the timer object yourself. Its lifetime is handled internally by the runloop.
Consider using scrollViewDidEndDecelerating method to avoid the frequent updates. Alloc-init is not responsible for the performance decrease, setting the text frequently is. Unless you really need to change it continuously (in which case solution with a timer might be an option), you should be looking for a different hook method.
You've got poor performance absolutely not because of the string formatting or alloc-release. You can use some shorter form like:
years.text = [NSString stringWithFormat:#"%0.1f", theScroller.contentOffset.y];
which is equivalent to
years.text = [[[NSString alloc] initWithFormat:#"%0.1f", theScroller.contentOffset.y] autorelease];
However this won't help to improve your performance at all.