Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Jules2010

macrumors member
Original poster
Apr 7, 2010
34
0
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
 
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.
 
... 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.

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];
}
 
This one...

Code:
- (void) playSoundShowLabel:(NSTimer*)theTimer

The warning ...

warning: incompatible Objective-C types initializing 'struct NSTimer *', expected 'struct NSString *'
 
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.
 
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
 
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
 
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.
 
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.

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.
 
I guess there was two errors and not one.
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...
 
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.
 
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.
 
I don't think you should be releasing theTimer in playSoundShowLabel: since you never retained it.
 
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");
}
 
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.

Have you followed robbieduncan's advice yet?

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.

Then report back when you have.
 
Have you followed robbieduncan's advice yet?
Then report back when you have.

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
 
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.
 
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!
 
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.
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.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.