0
votes

I am a newbie in objective-c and having trouble with NSTimer. While learning objective-c by developing games, I tried to move sprite using left and right button with the help of NSTimer. But, as it seems the selector is not being called. I searched stack overflow and found some solutions, but any solutions I've seen, not working. Here is my code-

#import "GameViewController.h"

@interface GameViewController ()
@property (strong) UIImage *playerImage;
@property (strong) UIImageView *playerView;
@property (strong) NSTimer *moveTimer;
@property CGRect playerRect;
@property int count;
@end

@implementation GameViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.count=0;
    self.playerImage = [UIImage imageNamed:@"ship.png"];
    self.playerView = [[UIImageView alloc] initWithImage: self.
                       playerImage];
    self.playerRect = CGRectMake(50,400, 32,32);
    self.playerView.frame = self.playerRect;
    [self.view addSubview: self.playerView];

//   this timer calls selector
//    self.moveTimer = [NSTimer scheduledTimerWithTimeInterval:.03
//                                             target:self
//                                           selector:@selector(movePlayerRight:)
//                                           userInfo:nil
//                                            repeats:YES];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


- (IBAction)moveLeft:(id)sender {
    [self releaseTouch];
    NSLog(@"Left Move");
//this timer does not call selector
    self.moveTimer = [NSTimer scheduledTimerWithTimeInterval:.03
                                                      target:self
                                           selector:@selector(movePlayerLeft:)
                                                    userInfo:nil
                                                     repeats:YES];
//    [[NSRunLoop mainRunLoop] addTimer:self.moveTimer forMode:NSDefaultRunLoopMode];
//    [[NSRunLoop mainRunLoop] run];
    //[self.moveTimer fire];
}

- (IBAction)moveRight:(id)sender {
    [self releaseTouch];
    NSLog(@"Right Move");
//    if(![NSThread isMainThread])
//        dispatch_async(dispatch_get_main_queue(), ^{
//this timer does not call selector
    self.moveTimer = [NSTimer scheduledTimerWithTimeInterval:.03
                                                      target:self
                                           selector:@selector(movePlayerRight:)
                                                    userInfo:nil
                                                     repeats:YES];

}

- (IBAction)TouchRelease:(id)sender {
    [self releaseTouch];
}

-(void) movePlayerRight:(NSTimer*)timer {
    NSLog(@"Right Move Selector");
    if(self.playerRect.origin.x <= 320){
        self.playerRect = CGRectOffset(self.playerRect, 3, 0);
        self.playerView.frame = self.playerRect;
    }
}
-(void) movePlayerLeft:(NSTimer*)timer {
    NSLog(@"Left Move Selector");
    if(self.playerRect.origin.x >= 10){
        self.playerRect = CGRectOffset(self.playerRect, -3, 0);
        self.playerView.frame = self.playerRect;
    }
}
-(void)releaseTouch{
    if(self.moveTimer != nil){
        [self.moveTimer invalidate];
        self.moveTimer = nil;
    }
}
@end

Let me explain what I've tried.

  1. I tried with scheduledTimerWithTimeInterval, as shown in code. But it won't work.
  2. Then I tried timerWithTimeInterval then with NSRunloop. Without NSRunloop [moveTimer fire] fires but NSRunLoop with repeats, it does not.
  3. Then, in a solution, I found that, thread might be creating problem; So, I tried-

    if(![NSThread isMainThread])
    dispatch_async(dispatch_get_main_queue(), ^{
    

    But, this is not the case with the thread, as the debugger does not step in the "dispatch_async" line.

  4. To see actually the NSTimer works, I even ran in the "viewDidLoad" method and it works.

What am I doing wrong?

**Solution: ** As suggested by @Danil Valeev and @aman.sood unchecked the Storyboard auto-layout, changed the property to 'nonatomic'; and now selector is being called from timer :)

2
Which timer isn't working? The one commented out in viewDidLoad? The one in moveLeft: or the one in moveRight:? Which selector isn't being called?rmaddy
selector in moveLeft and moveRight are not being called. the commented method is to support my point 4 in the question.user1993426
What is supposed to call moveLeft: and moveRight:? If those methods are never called then your timers are never started.rmaddy

2 Answers

2
votes

Check that movePlayerRight: or movePlayerLeft: are called. And that Auto Layout is not using in the view (I think it is the reason). You can disable Auto Layout in the xib/storyboard file in the first tab of Utilities.

0
votes

Replace [NSRunLoop mainRunLoop] with [NSRunLoop currentRunLoop] it should work