Grand Central Dispatch problems with dispatch_release - iphone

I have a problem with a GCD solution I've made. I have a thread that runs in the background, it updates the application in a given interval. For this I use a timer.
However if the user wants to change this interval, I call
dispatch_source_cancel(timer);
Which is defined as
dispatch_source_set_cancel_handler(timer, ^{
dispatch_release(timer);
});
And then restart the the thread. When the interval is changed a second time the app crashes. Even though I do recreate the timer with a new interval.
I could avoid releasing the timer, but then I'll have memory leeks.
Any advice, what to do?
EDIT:
Timer is created like this
timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,0,0, autoRefreshQueue);
if(!timer) {
return;
}
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, refreshRate * NSEC_PER_SEC), refreshRate * NSEC_PER_SEC, refreshRate * NSEC_PER_SEC);
dispatch_source_set_event_handler(timer, ^{
//do work
});

I don't think this is the answer. dispatch_source_cancel doesn't cancel immediately, synchronously.
man dispatch_source_cancel
The dispatch_source_cancel() function asynchronously cancels the dispatch source, preventing any further invocation of its event handler block. Cancellation does not interrupt a currently executing handler block (non-preemptive).
Thus, restarting the thread might invoke the blocks concurrently if autoRefreshQueue is Global Queue.
How did you restart the thread?
EDITED:
However there are no mentions of calling dispatch_source_set_timer twice (or more) for the same Dispatch Source in the references or the manuals, dispatch_source_set_timer in libdispatch/src/source.c seems ok for it. At least, as far as my test, there are no problem.
Thus, just call dispatch_source_set_timer for a new interval.
dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, refreshRate * NSEC_PER_SEC), refreshRate * NSEC_PER_SEC, refreshRate * NSEC_PER_SEC);

Related

dispatch_after time triggers immediately

This is the first time I've used GCD, I'll admit, so sorry if I've been stupid. I have a dispatch_after command which acts as a handy delay for me.
My problem is that when I send
dispatch_after(500000000000, dispatch_get_main_queue()){
println("triggered") //or any other code
}
the closure is triggered immediately (e.g. I have tested this and "triggered" prints immediately). It should take longer right? Like 500 seconds longer.
Thanks :)
The first parameter of dispatch_after(_:_:_:) is not a delay, but a point in time. From the docs:
when: The temporal milestone returned by dispatch_time or dispatch_walltime.
Discussion
This function waits until the specified time and then asynchronously
adds block to the specified queue.
You need to construct a delay relative to the current time, using dispatch_time(_:_:):
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(500 * NSEC_PER_SEC))
dispatch_after(delayTime, dispatch_get_main_queue()) { ... }

iPhone iOS how to implement a sequence of background network send operations in the fastest way possible?

I'm trying to stream data to a server at regular intervals and do so in a way that is fast and does not block the UI. The UI is also pretty busy trying to display the data. Currently my implementation uses NSTimer that fires every 50ms, picks a network packet out of a circular array and sends it over:
//this is the timer
networkWriteTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:#selector(sendActivity:) userInfo:nil repeats:YES];
-(void)sendActivityInBackground:(id)sender
{
[[AppConfig getInstance].activeRemoteRoom.connection sendNetworkPacket:[circularArray objectAtIndex:arrayIndex%arrayCapacity]];
}
-(void)sendActivity:(NSTimer*)timer
{
// Send it out
[self performSelectorInBackground:#selector(sendActivityInBackground:) withObject:nil];
}
I'm not satisfied with the performance of this method. Time profiling has revealed that there's overhead associated with performing background selectors, and the performance can get quite choppy.
I'm thinking of additional ways to improve performance:
Improve the performance of the current timer based code
Try grand central dispatch
Implement NSOperationsQueue with a single operation.
Use a dedicated thread that wakes up, checks for update and sends it over if needed
Ideally, I would send data at even faster intervals (10ms or even for each activity update). This poses the question: What is the fastest way to implement a sequence of background send requests, where order matters? I want to make sure that one packet gets send before the next one is being sent.
Try a recurring dispatch timer (that is part of gcd):
self.synchronizerQueue = dispatch_queue_create("synchronizer queue", DISPATCH_QUEUE_SERIAL);
self.synchronizeTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.synchronizerQueue);
dispatch_source_set_timer(self.synchronizeTimer, DISPATCH_TIME_NOW, NSEC_PER_MSEC * 10, NSEC_PER_MSEC * 1);
dispatch_source_set_event_handler(self.synchronizeTimer, ^
{
// do your processing here
});
dispatch_resume(self.synchronizeTimer);

Objective-c/iOS: setting status text in async function is slow

In my app I'm doing some communication with a remote server and as this might be slow I thought it would be a good idea to run that code asynchronously. I have my communication code in a block that I pass to dispatch_async. This code does the communication and when it's done it sets the text of a label. This last part is the problem. The text is set, but it occurs after a delay of a few seconds. This is my code.
- (void)doNetworkingTask {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Slow network task goes here.
// Slow network task done, notify the user.
[self.myLabel setText:#"task done."];
NSLog(#"task done.");
});
}
What happens here is that my network task completes, the NSLog-text is logged and after a couple of seconds, the text of the label is updated. My question is 1) why does the label text not update instantly? and 2) what is a proper way of doing what I want to do? (do the slow network task without blocking anything else, update the user through a text label once I'm done.)
UI updates must be on the main thread. Update your code to something like this:
- (void)doNetworkingTask {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// Slow network task goes here.
// Slow network task done, notify the user.
dispatch_async(dispatch_get_main_queue(), ^{
[self.myLabel setText:#"task done."];
});
NSLog(#"task done.");
});
}

Multiple GCD Dispatches on main thread

I'm trying to speed up the boot of my app, and one of the ideas i had for that was to use asynchronous dispatch queues. I have 2 tasks that can be run next to each other at startup (quite big tasks actually). However, both of them have a significant part that runs on the main thread (UI code mainly).
dispatch_async(dispatch_get_main_queue, ^{
[self doTask1];
});
dispatch_async(dispatch_get_main_queue, ^{
[self doTask2];
//Will task 2 take turns with task 1, or will task 2 start after 1 is finished?
});
My question is this: If i call 2 dispatch_async's at boot like in this example, will they take turns in executing, or will the complete first block execute first, then the 2nd block?
the main queue is a serial queue. blocks added to serial queues are executed in the order they are added and only one at a time (serially). in your example, task2 will not start until task1 has finished.
if you want them to run concurrently you'll need to dispatch them to one of the global concurrent queues.
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(q, ^{/* this work may finish before other work added to this queue later */});
One will be executed after the other, but they will execute concurrently, meaning you can execute task2 before task1 has finished.
Check the alternative:
dispatch_async(dispatch_get_main_queue, ^{
[self doTask1];
dispatch_async(dispatch_get_main_queue, ^{
[self doTask2];
//Now task2 will execute after task1
});
});

How to make a static image appear after 3 seconds?

How would I make an image appear after 3 seconds?
You can use:
[self performSelector: withObject: afterDelay: ]
I'm a big fan of using GCD (iOS 4+) because you can simplify your code with inline blocks.
In your case, you should set the image to hidden in Interface Builder, then create an IBOutlet with a connection to an ivar in your class.
Then you can simply run this in viewDidLoad or similar:
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 3.0);
dispatch_after(delay, dispatch_get_main_queue(), ^(void){
yourImage.hidden = NO;
});
This assumes that you are calling performSelector:withObject:afterDelay from the main thread, and that your UIImageView is initially hidden.
//assumes theImageView.hidden = YES
[self performSelector:#selector(showImage:) withObject:theImageView afterDelay:yourTimeInterval];
-(void)showImage:(UIImageView*)anImageView {
anImageView.hidden = NO;
}
It is important that performSelector is called from the main thread because the selector that is called after the delay will run on the same thread, and you do not want to update UI from anything other than the main thread as a general rule.
I haven't used XCode in awhile, but I'll take a stab for ya..
In your Interface Builder set the image's visibility as hidden
When your app starts up, set some global variable to the current time in an init fxn
In the main control loop for your UI, check if that global var contains a time that is more than 3 seconds ago, if so, change that image's visibility parameter to shown.
Best I can really say without really taking a look, which isn't possible right now.
Good luck!