problems with new thread - ios

After trying many ways to call a function in new thread only the below code worked for me
[NSThread detacNewThreadSelector:#selector(temp:) toTarget:self withObject:self];
The below didn't work:
NSThread *updateThread1 = [[NSThread alloc] initWithTarget:self selector:#selector(temp:) object:self];
NSThread *updateThread1 = [[NSThread alloc] init];
[self performSelector:#selector(temp:) onThread:updateThread1 withObject:self waitUntilDone:YES];
Now when i try to call NSTimer or perform selector in timer: function it does not works Find below the code
int timeOutflag1 = 0;
-(void)connectCheckTimeOut
{
NSLog(#"timeout");
timeOutflag1 = 1;
}
-(void)temp:(id)selfptr
{
//[selfptr connectCheckTimeOut];
NSLog(#"temp");
//[NSTimer scheduledTimerWithTimeInterval:5 target:selfptr selector:#selector(connectCheckTimeOut) userInfo:nil repeats:NO];
[selfptr performSelector:#selector(connectCheckTimeOut) withObject:nil afterDelay:5];
}
- (IBAction)onUart:(id)sender {
protocolDemo1 *prtDemo = [[protocolDemo1 alloc] init];
//NSThread *updateThread1 = [[NSThread alloc] initWithTarget:self selector:#selector(temp:) object:self];
//[self performSelector:#selector(temp:) onThread:updateThread1 withObject:self waitUntilDone:YES];
// [updateThread1 start];
[self performSelector:#selector(temp:) withObject:self afterDelay:0];
while(1)
{
NSLog(#"Whieloop");
if(timeOutflag1)
{
timeOutflag1 = 0;
break;
}
if([prtDemo isConnected])
break;
}
}
If i use [self performSelector:#selector(connectCheckTimeOut) withObject:nil afterDelay:5];
in onUart function then it works properly i can see Timeout printf but inside temp it does not work.

NSTimer is run-loop based, so if you want to use one on a background thread that you're spawning and managing yourself, you will need to start a runloop on that thread. Read up on NSRunLoop. The short version might look something like:
- (void)timedMethod
{
NSLog(#"Timer fired!");
}
- (void)threadMain
{
NSRunLoop* rl = [NSRunLoop currentRunLoop];
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval: 1.0 target: self selector: #selector(timedMethod) userInfo:nil repeats:YES];
[rl run];
}
- (void)spawnThread
{
[NSThread detachNewThreadSelector: #selector(threadMain) toTarget:self withObject:nil];
}

Related

iOS: Why can I not call performSelector to execute the same function where it is called?

When I use [self performSelector:#selector(checkFirstSynchro) withObject:nil afterDelay:30.0]; in the checkFirstSynchro function, it seems not to work. Is it because it is in a Class function?
-(void) viewDidLoad
{
...
[self checkFirstSynchro]
...
}
- (void) checkFirstSynchro
{
//Check if firstSynchro
BOOL firstSynchro = [[[NSUserDefaults standardUserDefaults] valueForKey:#"FirstSynchro"] boolValue];
if (!firstSynchro)
{
[Reachability checkInternetConnectivityWithSuccessCompletion:^(NSError *error) //test if there is internet c
onnection
{
if (error == nil)
{
[self sync:connectBtn];
}
else
{
[self performSelector:#selector(checkFirstSynchro) withObject:nil afterDelay:30.0];
}
}];
}
}
It launches well the function, but it doesn't execute the perform 30.0 seconds later.
I tried this instead of the performSelector, but without success:
[NSTimer scheduledTimerWithTimeInterval:TIMER_FIRST_SYNCHRO
target:self
selector:#selector(checkFirstSynchro)
userInfo:nil
repeats:NO];
It launches well the function, but it doesn't execute the [NSTimer scheduledTimerWithTimeInterval 30.0 seconds later.
Thanks in advance.

pass block as parameter in my case

I have a function which takes a block as parameter:
typedef void (^ MyBlock)(int);
-(void)doTask:(MyBlock)theBlock{
...
}
I need to run above function on another thread, I want to use - performSelector:onThread:withObject:waitUntilDone: , my current code:
NSThread *workerThread = [[NSThread alloc] init];
[workerThread start];
[self performSelector:#selector(doTask:)
onThread:workerThread
withObject:???
waitUntilDone:NO];
BUT, How can I pass MyBlock parameter with this approach? (Please don't suggest GCD, I am wondering how can I do with my current code, is it possible?)
This answer assumes you are using ARC. If you are not then you need to do a little more, but overall the answer is the same.
BUT, How can I pass MyBlock parameter with this approach?
A block is an object, you don't need to do anything special. E.g.:
[self performSelector:#selector(doTask:)
onThread:workerThread
withObject:^(int arg){ NSLog(#"block passed: %d", arg); }
waitUntilDone:NO];
HTH
[self performSelector:#selector(someMethod)
onThread:[Your thread]
withObject:[your object]
waitUntilDone:NO];
-(void)someMethod
{
[self doTask:^(int intValue) {
// Do your task
}];
}
First create thread like this so that it is alive and you can call methods from that thread
-(void) myThreadMainMethod: (id) sender {
#autoreleasepool {
NSRunLoop *runloop = [NSRunLoop currentRunLoop];
[runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
while (true) { // add your condition for keeping the thread alive
[runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
}
}
NSThread* workerThread = [[NSThread alloc] initWithTarget:self
selector:#selector(myThreadMainMethod:)
object:nil];
[workerThread start];
Then write something like this
-(void)doTask:(MyBlock)theBlock{
NSLog(#"do task called now execute the block");
theBlock(1);
}
MyBlock block1 = ^(int a) {
NSLog(#"integer %i", a);
};
[self performSelector:#selector(doTask:)
onThread:[NSThread mainThread]
withObject:block1
waitUntilDone:NO];

SocketScan always returns 100% battery life

I'm getting 100% as the result every time...why (iOS/ SocketScan API v.10.2.227)?
Here's my code:
-(void) onGetBatteryInfo:(ISktScanObject*)scanObj {
SKTRESULT result=[[scanObj Msg]Result];
if(SKTSUCCESS(result)){
long batteryLevel = SKTBATTERY_GETCURLEVEL([[scanObj Property] getUlong]);
NSLog(#"BatteryInfo %ld", batteryLevel);
[self setBatteryLevel:batteryLevel];
[self.tableView reloadData];
} else {
NSLog(#"ES-GetBatteryInfo set status returned the error %ld",result);
}
}
Thanks,
Mark
Can you double check the following...
In viewDidLoad you create ScanApiHelper and a timer
if(ScanApi==nil) {
ScanApi=[[ScanApiHelper alloc]init];
[ScanApi setDelegate:self];
[ScanApi open];
ScanApiConsumer=[NSTimer scheduledTimerWithTimeInterval:.2 target:self selector:#selector(onTimer:) userInfo:nil repeats:YES];
}
Your timer calls doScanApiReceive
-(void)onTimer: (NSTimer*)theTimer{
if(theTimer==ScanApiConsumer){
[ScanApi doScanApiReceive];
}
}
Finally, you don't query the battery level until after you've received an onDeviceArrival notification
-(void)onDeviceArrival:(SKTRESULT)result device:(DeviceInfo*)deviceInfo {
[ScanApi postGetBattery:deviceInfo Target:self Response:#selector(onGetBatteryInfo:)];
}

Can I use a NStimer in another NStimer?

I create a NSTimer:
timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(sendImage) userInfo:nil repeats:YES];
In the method sendImage, I create another NSTimer timer2. The code following:
- (void)sendImage
{
for(int i = 0;i < 50 ; i++)
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:socket forKey:#"socket"];//parameter which deliver to the method`sendPieceOfImage`
[dict setObject:pData forKey:#"pData"];
timer2 = [NSTimer scheduledTimerWithTimeInterval:0.002f target:self selector:#selector(sendPieceOfImage:) userInfo:dict repeats:NO];
}
}
But it didn't work. I want to know can NSTimer apply mechanically? If it's infeasible, what can I do in the sendImage. I hope every cycle in the for() can run with interval.
The answer to your question is YES. That's possible to schedule one timer in the firing callback of another. Consider this:
dispatch_async(dispatch_get_main_queue(), ^{
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timer1Event:) userInfo:nil repeats:YES];
});
- (void)timer1Event:(NSTimer*)timer {
NSLog(#"timer1Event");
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(timer2Event:) userInfo:nil repeats:NO];
}
- (void)timer2Event:(NSTimer*)timer {
NSLog(#"timer2Event");
}
Even the problem is not fully described, I'll try to guess that the rootcause is in how very first timer is scheduled.
You need thread with aproprietaly setted up RunLoop. Main thread is suitable.
dispatch_async(dispatch_get_main_queue(), ^{
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:#selector(sendImage) userInfo:nil repeats:YES];
});
If you don't want to load the main thread, consider this:
You need your own thread:
self.workerThread = [[NSThread alloc] initWithTarget:self selector:#selector(startRunLoop) object:nil];
[self.workerThread start];
Which starts the runloop:
- (void)startRunLoop
{
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
do {
#autoreleasepool
{
[runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
}
} while (![NSThread currentThread].isCancelled);
}
Now, for starting the timer on the worker thread you need this:
- (void)startTimer
{
self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:#selector(timerEvent:) userInfo:nil repeats:YES];
}
How to call:
[self performSelector:#selector(startTimer) onThread:self.workerThread withObject:nil waitUntilDone:NO];
Hope it helps.

how to make NSTimer consistent on xcode

I'm making a game and would like to use a timer to countdown an event, just like what's seen on Bejeweled. I know that I've to put NSTimer in a NSRunLoop to make it work, since NSTimer is inaccurate. Have tried the following but it still don't work. Please help!
#import ...
NSTimer *_gameTimer;
int secondsLeft;
//some code
//called countdownTimer using [self countdownTimer];
- (void)countdownTimer
{
_gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
NSRunLoop *gameRun = [NSRunLoop currentRunLoop];
[gameRun addTimer:_gameTimer forMode:NSDefaultRunLoopMode];
}
- (void)updateTime:(NSTimer *)timer
{
if (secondsLeft>0 && !_gameOver) {
_timerLabel.text = [NSString stringWithFormat:#"Time left: %ds", secondsLeft];
secondsLeft--;
} else if (secondsLeft==0 && !_gameOver) {
// Invalidate timer
[timer invalidate];
[self timerExpire];
}
}
- (void)timerExpire
{
// Gameover
[self gameOver];
[_gameTimer invalidate];
_gameTimer = nil;
}
NSTimer needs to be a local variable so there can only be one instance of the object running through the loop. Here's the code.
- (void)countdownTimer
{
NSTimer *_gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTime:) userInfo:nil repeats:YES];
NSRunLoop *gameRun = [NSRunLoop currentRunLoop];
[gameRun addTimer:_gameTimer forMode:NSDefaultRunLoopMode];
if (secondsLeft==0 || _gameOver) {
[_gameTimer invalidate];
_gameTimer = nil;
}
}
- (void)updateTime:(NSTimer *)timer
{
if (secondsLeft>0 && !_gameOver) {
_timerLabel.text = [NSString stringWithFormat:#"Time left: %ds", secondsLeft];
secondsLeft--;
} else if (secondsLeft==0 || _gameOver) {
// Invalidate timer
[timer invalidate];
[self timerExpire];
}
- (void)timerExpire
{
// Gameover
[self gameOver];
}

Resources