NSTimer changes in SDK, scheduledTimerWithTimeInterval

Discussion in 'iOS Programming' started by Jules2010, Apr 7, 2010.

  1. Jules2010 macrumors member

    Joined:
    Apr 7, 2010
    #1
    Code:
    NSString *rowAsString = [NSString stringWithFormat: @"%d", row];
    		
    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:accumSecs
    	target:self selector:@selector(playSoundShowLabel:) 
    	userInfo:rowAsString repeats:NO];
    		
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    {
    
    }
    Hi,

    I've been trying to play some sounds at timed intervals. However I'm getting a warning, which is the only thing I have to go on.

    warning: incompatible Objective-C types initializing 'struct NSTimer *', expected 'struct NSString *'

    When the code runs I get this error status.

    Program received signal: “EXC_BAD_ACCESS”.

    I've checked around and found code with this syntax in a couple of places, I was also able to get it working in a test project, however I can't track down the problem.

    TIA
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    I've no idea what your title is about: as you say yourself you can get this working so there are no "changes in SDK": this is an error in your code plain and simple.

    The compiler is telling you that you have a type mismatch. Most likely you have multiple variables with the same name or something similar. As you have only pasted tiny snippets of code we can't really tell or help.
     
  3. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #3
    Right, I just can't see it, there not much more of my code.

    Code:
    - (IBAction)buttonPressed:(id)sender
    {
    	int row =1;
    	float accumSecs = 0;
    	
    	for (row = 1; row < 12; row++) {
    		
    		NSString *rowAsString = [NSString stringWithFormat: @"%d", row];
    		
    		NSTimer *timer = [NSTimer 
    			scheduledTimerWithTimeInterval:accumSecs
    			target:self selector:@selector(playSoundShowLabel:) 
    			userInfo:rowAsString repeats:NO];
    		
    		//TODO
    	}
    }
    
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    {
    	NSString *rowAsString = [theTimer userInfo];
    	
    	//TODO
    
    	[rowAsString release];
    	[theTimer release];
    }
     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
  5. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #5
    This one...

    Code:
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    The warning ...

    warning: incompatible Objective-C types initializing 'struct NSTimer *', expected 'struct NSString *'
     
  6. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #6
    Can you post the entire .h and .m files? I can't tell from the small amounts you have posted what is wrong. What, exactly, is in the .h file for this? Specifically have you defined playSoundShowLabel: differently.
     
  7. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #7
    OK.

    Code:
    //
    //  LearnViewController.h
    //  TestNavBasedApp
    //
    
    #import <AudioToolbox/AudioToolbox.h>
    #import <UIKit/UIKit.h>
    
    
    @interface LearnViewController : UIViewController {
    	IBOutlet UIView *placeholderView;
    	
    }
    @property (nonatomic, retain) UIView *placeholderView;
    - (IBAction)buttonTable1Pressed:(id)sender;
    - (float) getTrackLength:(NSString *)str;
    - (void) playSoundShowLabel:(NSString *) str;
    
    @end
    
    Code:
    //
    //  LearnViewController.m
    //  TestNavBasedApp
    //
    
    #import "LearnViewController.h"
    #import "SoundEffect.h";
    #import "Constants.h";
    
    @implementation LearnViewController
    @synthesize placeholderView;
    
    
    - (IBAction)buttonTable1Pressed:(id)sender
    {
    	int row =1;
    	float accumSecs = 0;
    	
    	for (row = 1; row < 12; row++) {
    		
    		NSString *rowAsString = [NSString stringWithFormat: @"%d", row];
    		
    		NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:accumSecs
    					target:self selector:@selector(playSoundShowLabel:) userInfo:rowAsString repeats:NO];
    		
    	}
    	
    	
    	UILabel *lbl = (UILabel *)[placeholderView viewWithTag:112];
    	lbl.text = [NSString stringWithFormat:@"%i. ", 99];	
    	
    	lbl.text = [NSString stringWithFormat:@"%i. ", [self getTrackLength:@"1"]];		
    			
    }
    
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    {
    	NSString *rowAsString = [theTimer userInfo];
    	
    	[rowAsString release];
    	[theTimer release];
    	
    }
    
    /*
     // The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
        if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
            // Custom initialization
        }
        return self;
    }
    */
    
    
    // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
    - (void)viewDidLoad {
        [super viewDidLoad];
    	
    }
    
    /*
    // Override to allow orientations other than the default portrait orientation.
    - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
        // Return YES for supported orientations
        return (interfaceOrientation == UIInterfaceOrientationPortrait);
    }
    */
    
    - (void)didReceiveMemoryWarning {
        // Releases the view if it doesn't have a superview.
        [super didReceiveMemoryWarning];
        
        // Release any cached data, images, etc that aren't in use.
    }
    
    - (void)viewDidUnload {
        [super viewDidUnload];
        // Release any retained subviews of the main view.
        // e.g. self.myOutlet = nil;
    }
    
    
    - (void)dealloc {
        [super dealloc];
    }
    
    
    @end
    
     
  8. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #8
    Well there you go. It's staring you right in the face.

    .h file
    Code:
    - (void) playSoundShowLabel:(NSString *) str;
    
    .m file
    Code:
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    
     
  9. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #9
    Ahhh right thanks, that warning has gone now.

    But I'm still getting...

    Program received signal: “EXC_BAD_ACCESS”.

    I guess there was two errors and not one.

    I took out the for loop, just in case, but that didn't solve the problem.
     
  10. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #10
    Look, this is debugging. You're just meant to do it. We can't do it for you. When it crashes open the debugger, find out where the crash occurs and work backwards till you find the error. Most likely you are sending a message to an object that is no longer in memory as you have not managed your memory correctly.

    Debugging is a core programming skill. Time to learn it.
     
  11. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #11
    EXC_BAD_ACCESS is never going to be detected as a compile-time error. And anyways, the compiler sometimes cannot detect all errors when building because one error is masking others. You just need to realize that this is an iterative process and you need to fix errors, re-build, fix more errors, until you have code that compiles. Then you get to deal with the run-time errors...
     
  12. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #12
    Absolutely, I'm sure Robert was right I'm sure, that its something to do with memory management.

    I've tried to follow the example I found originally, but its not working out for me.

    I'm quietly confident that the for loop is cause the problem, but I can imagine a loop maybe higher up would be common use.
     
  13. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #13
    First thing I notice that is wrong is that in playSoundShowLabel: you have

    Code:
    [rowAsString release];
    
    You did not create this via alloc/init or copy so you should not be releasing it. Follow these very simple rules and you should be OK.
     
  14. rossipoo macrumors regular

    Joined:
    Jun 7, 2009
    #14
    I don't think you should be releasing theTimer in playSoundShowLabel: since you never retained it.
     
  15. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #15
    Hmmm, I do need to retain rowAsString, therefore I need to release it. The theTimer in playSoundShowLabel needs to invalidate'd I believe.

    However, this doesn't get me much further when I use the button a second time or return to the previous screen via the navigation controller I get the EXC_BAD_ACCESS error.

    Code:
    - (IBAction)buttonTable1Pressed:(id)sender
    {
    	int row =1;
    	float accumSecs = 0;
    	//NSTimer *timer;
    	
    	NSString *rowAsString;
    	
    	for (row = 1; row < 12; row++) {
    		
    		rowAsString = [[NSString stringWithFormat: @"%d", row] retain];
    		
    		//NSLog(@"log: one\n");
    		
    		NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:accumSecs
    			target:self selector:@selector(playSoundShowLabel:) 
    			userInfo:rowAsString repeats:NO];
    		
    		//NSLog(@"log: two\n");
    	}
    	//[timer release];
    	
    	
    	UILabel *lbl = (UILabel *)[placeholderView viewWithTag:112];
    	lbl.text = [NSString stringWithFormat:@"%i. ", 99];		
    	lbl.text = [NSString stringWithFormat:@"%i. ", [self getTrackLength:@"1"]];
    	
    	[lbl release];
    	
    	//NSLog(@"log: end\n");	
    }
    - (void) playSoundShowLabel:(NSTimer*)theTimer
    {
    	//NSLog(@"log: three\n");
    	NSString *rowAsString = [theTimer userInfo];
    	//NSLog(@"log: four\n");
    	
    	//snip
    	
    	[rowAsString release];
    	[theTimer invalidate];
    	
    	//NSLog(@"log: five\n");
    }
     
  16. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #16
    Have you followed robbieduncan's advice yet?

    Then report back when you have.
     
  17. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #17
    Yes I have, the debugger tells me very little, in fact it works the first time.
    The second time, when the button is pressed, it doesn't run the the scheduled function.

    The only thing I have, which I don't think is relevant is this...

    modifying layer that is being finalized

    From the console window, but this happens in the first button pressed and doesn't cause a problem
     
  18. Luke Redpath macrumors 6502a

    Joined:
    Nov 9, 2007
    Location:
    Colchester, UK
    #19
    You shouldn't be releasing rowAsString in playSoundShowLabel: as you are not retaining it anywhere (the NSTimer *might* be retaining it but thats NSTimer's concern). Likewise, the timer isn't retained and will be auto-released, so do not release it.

    UPDATE: ok, I misread your code and it seems you *are* releasing it for reasons I cannot understand.

    Code:
    rowAsString = [[NSString stringWithFormat: @"%d", row] retain];
    
    Why retain it? You are passing it into the NSTimer's userInfo parameter, which will presumably retain or copy it so you can access it later in your callback.

    Remove the retain here, and the release from the callback. There is no guarantee that the userInfo method in the callback is returning a pointer to the same object (it could be a copy), so a) releasing it will cause the EXC_BAD_ACCESS error you are seeing and b) the retained rowAsString will leak.
     
  19. Jules2010 thread starter macrumors member

    Joined:
    Apr 7, 2010
    #20
    Thanks Luke,

    As a result of your reply I managed to fix the problem.

    I tried removing the items you suggested and at the same time...
    Code:
    [lbl release];
    I tried putting those retain and release back that you mentioned and the code worked.

    To be honest, I'm sure I look lbl release out and still had the problem, but I've tried that many thing, I can't be sure.

    Thanks all of you!
     
  20. dejo Moderator

    dejo

    Staff Member

    Joined:
    Sep 2, 2004
    Location:
    The Centennial State
    #21
    Doesn't seem you are using the debugger correctly then. You should be able to use it to track down the exact line in your code where it is crashing.
     

Share This Page