Cancel completion block after delay - ios

There is block that discovering CBServices of some CBPeripheral (CoreBluetooth). But how can I cancel this block after some time has passed?
For example, if it has not discover CBServices after 10 seconds my block must be cancel.

You can use performSelector for delay action
[self performSelector:#selector(cancelAction:) withObject:self afterDelay:10];
-(void)cancelAction:(id)sender {
//What ever you want try here
}

Just call stopScan function of CBCentralManager.
[self performSelector:#selector(stopScan:) withObject:self afterDelay:10];
- (void)stopScan:(id)sender {
[self.centralManager stopScan];
}

Related

performSelector being called but not performSelector:afterDelay

This code works, and postSpamListUpdatedNotification is called
- (void) postSpamListUpdatedNotification
{
[NIDPrivateUtils postNotification:kNIDSpamListsUpdated andError:nil];
}
[self performSelector:#selector(postSpamListUpdatedNotification) withObject:nil];
But if I change it to this, then postSpamListUpdateNotification is never called. Why?
[self performSelector:#selector(postSpamListUpdatedNotification) withObject:nil afterDelay:2.0];
You likely don't have a runloop on this thread. performSelector:withObject:afterDelay: requires a runloop, but performSelector: doesn't.

How to execute a function before an NSOperation is cancelled in NSOperationQueue

I want to execute a function before an NSOperation is cancelled. In main function, I add below code to achieve this goal:
if (self.isCancelled) {
[self doSomething];
return;
}
But if I cancel an operation before its start method is called, where should I call doSomething?
For queued operations, it simply marks the operation as ready to
execute and lets the queue call its start method, which subsequently
exits and results in the clearing of the operation from the queue.
According to above Apple's document, I know that I can call doSomething in start function, so am I right?
- (void)start {
if (self.isCancelled) {
[self doSomething];
}
[super start];
}
I would set the code you want to run in the completionblock.

How can I add a delay before it continues

Is there a way in the normal obj-c or cocos2d to make a delay inside a if-else block?
Like
if ([self isValidTileCoord:cTileCoord] && ![self isWallAtTileCoord:cTileCoord])
{
[self addChild:circle0];
//wait two seconds
//perform another task
}
Just a simple lag to wait between two tasks, or stalling an action. Is there any simple way to do this?
There are many ways to do this. I would use GCD
if ([self isValidTileCoord:cTileCoord] && ![self isWallAtTileCoord:cTileCoord])
{
[self addChild:circle0];
//wait two seconds
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{
//perform another task;
});
}
You can use the performSelector: withObject: afterDelay: method to delay tasks:
if ([self isValidTileCoord:cTileCoord] && ![self isWallAtTileCoord:cTileCoord])
{
[self addChild:circle0];
//wait two seconds
[self performSelector:#selector(continueTask) withObject:nil afterDelay:2.0];
}
And in the selector method:
-(void)continueTask
{
//perform another task
}
Inside the cocos2d you can also run an Action on the node like,
[self runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2.0],[CCCallFunc actionWithTarget:self selector:#selector(anothertaks)],nil]];
Perform selector will also work but the problem is that all the schedulers of cocos2D get paused when the app go to background but on the other side perform selector will still count the time, so some time it create task,animation,etc syncing problems.
Perform selector:
[self performSelector:#selector(continueTask) withObject:nil afterDelay:2.0];

Dealing with two screens and one activity indicator in iOS

I have 3 screens on my app.First is login. Second is search and third is process the task.
On login i retrieve data from a web service. It returns data in XML format. So the data is considerably large. So i am doing that task on a background thread like this to stop Mainthread freezing up on me:
-(BOOL)loginEmp
{
.....some computation
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
(unsigned long)NULL), ^(void) {
[self getAllCustomerValues];
});
}
-(void)getAllCustomerValues
{
....more computation.Bring the data,parse it and save it to CoreData DB.
//notification - EDIT
NSNotification *notification =[NSNotification notificationWithName:#"reloadRequest"
object:self];
[[NSNotificationCenter defaultCenter] postNotification : notification];
}
//EDIT
//SearchScreenVC.m
- (void)viewDidLoad
{
....some computation
[self.customerActIndicator startAnimating];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(stopActivityIndicator)
name:#"reloadRequest"
object:nil];
}
- (void)stopActivityIndicator
{
[self.customerActIndicator stopAnimating];
self.customerActIndicator.hidesWhenStopped = YES;
self.customerActIndicator.hidden =YES;
NSLog(#"HIt this at 127");
}
So on condition that login was successful, i move to screen 2. But the background thread is still in process( i know because i have logs logging values) . I want an activity indicator showing up here (2nd screen)telling user to wait before he starts searching. So how do i do it?How can i make my activity indicator listen/wait for background thread. Please let me know if you need more info.Thanks
EDIT: so I edited accordingly but the notification never gets called. I put a notification at the end of getAllCustomerValues and in viewDidLoad of SearchScreen i used it. That notification on 2nd screen to stop animating never gets called. What is the mistake i am doing.?Thanks
EDIT 2: So it finally hits the method. I dont know what made it to hit that method. I put a break point. I wrote to stop animating but it wouldn't. I wrote hidesWhenStoppped and hidden both to YES. But it still keeps animating.How do i get it to stop?
Ok, if it is not the main thread, put the following in and that should fix it.
- (void)stopActivityIndicator
{
if(![NSThread isMainThread]){
[self performSelectorOnMainThread:#selector(stopActivityIndicator) withObject:nil waitUntilDone:NO];
return;
}
[self.customerActIndicator stopAnimating];
self.customerActIndicator.hidesWhenStopped = YES;
self.customerActIndicator.hidden =YES;
NSLog(#"HIt this at 127");
}
Could you put your background operation into a separate class and then set a delegate on it so you can alert the delegate once the operation has completed?
I havent tried this, its just an idea :)
You could use a delegate pointing to your view controller & a method in your view controller like:
- (void) updateProgress:(NSNumber*)percentageComplete {
}
And then in the background thread:
float percentComplete = 0.5; // for example
NSNumber *percentComplete = [NSNumber numberWithFloat:percentComplete];
[delegate performSelectorOnMainThread:#selector(updateProgress:) withObject:percentageComplete waitUntilDone:NO];

iOS - Thread and alertiview

i've an app that when start control updates and other things. If the app find some updates they will ask user if this updates have to be done. If user select YES i want that a spinner appear on main screen until update finish. But when i tap YES my alert view doesn't disappear and remain on screen until update is finished.
Is it possible to create a thread that run on the main thread and stop when update in finished?
Thanks
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex==1) {
[self showActivityViewer];
[self downloadControlAndUpdatePoi];
[self downloadControlAndUpdateItinerari];
[self downloadControlAndUpdateArtisti];
[self downloadControlAndUpdateEventi];
[self hideActivityViewer];
NSLog(#"AGGIORNA");
} else {
NSLog(#"NON AGGIORNARE");
return;
}
}
If the methods
[self downloadControlAndUpdatePoi];
[self downloadControlAndUpdateItinerari];
[self downloadControlAndUpdateArtisti];
[self downloadControlAndUpdateEventi];
are executed synchronously (that means that they return only after having processed completely), so:
[self hideActivityViewer];
is executed only at the very end.
A simple approach to this is scheduling the execution of your methods on the main thread:
[self performSelector:#selector(downloadControlAndUpdatePoi) withObject:nil afterDelay:0];
....
[self hideActivityViewer];
so that those methods are executed only after control has returned to the main loop and the UI has been updated.
Otherwise, you could use:
+ detachNewThreadSelector:toTarget:withObject:
from NSThread, to do more or less the same. In this case I would suggest creating a wrapper method for all of your dowloadAndUpdate... methods, but keep in mind that you can't update the UI from a secondary thread.
In both cases, you should take some care about synchronizing the download... operations with the rest of your workflow after removing the alert view.

Resources