3

I developed an iPhone app under iOS 5.0, and it works fine. But when it comes to iOS 4.3(Base SDK = latest iOS 5.0, compiler = Apple LLVM 3.0, Deployment Target = iOS 4.3), it crashes after launching.

The output around crash point looks like:

2011-12-06 16:25:08.177 FMWei[466:c203] -[AVAudioSession setMode:error:]: unrecognized selector sent to instance 0x706a7f0
2011-12-06 16:25:08.181 FMWei[466:c203] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[AVAudioSession setMode:error:]: unrecognized selector sent to instance 0x706a7f0'

It looks like that AVAudioSession doesn't have a member function setMode:error: while I invoked it. But what's strange is that I didn't invoke a function whose name is setMode:error:. The code about audio processing is:

audio_session = [[AVAudioSession sharedInstance] retain];
audio_session_err = nil;
[audio_session setCategory: AVAudioSessionCategoryPlayAndRecord error:&audio_session_err];
NSLog(@"!");

UInt32 audioRouteOverride = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,sizeof (audioRouteOverride),&audioRouteOverride);
UInt32 allowMixing = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);    

if (audio_session_err) 
{
    NSLog(@"audioSession: %@ %d %@", [audio_session_err domain], [audio_session_err code], [audio_session_err description]);
}
else
{
    audio_session_err = nil;
    [audio_session setActive:YES error:&audio_session_err];
    if (!audio_session_err) NSLog(@"audio session is activated successfully");
}

Please help me figure out why it crashes under iOS 4.3 with the strange error. Thank you!

Timothy
  • 4,467
  • 5
  • 28
  • 51

3 Answers3

5

At runtime, lots of methods are called that are not in your code, but which are called behind the scenes as a result of the API calls you have made.

I would focus not on the method that is being called, but on why the object it is sent to is unable to respond to the selector. The object could have been cast as the wrong type, and so is not inheriting the right methods. (In the code snippet you show, you don't explicitly cast AVAudioSession *audio_session.) The other direction is to check that you're not using some other API call that is iOS 5 only, which in the background is calling this method and thus generating the error.

Finally, if you're only recently changed your build target to include iOS 4.3, you may simply need to do a clean build (Product > Clean) so that it compiles iOS 4.3-compatible code.

Duncan Babbage
  • 19,972
  • 4
  • 56
  • 93
  • Thank you Duncan:-) there is a `NSError *audio_session_err;` in the .h file. – Timothy Dec 06 '11 at 09:24
  • I casted `AVAudioSession *audio_session;` in the .h file, sorry for that I did't show that. – Timothy Dec 06 '11 at 09:56
  • is it possible that the AVFoundation.framework file which I included is for iOS 5.0 only, and it invokes something unfriendly? How can I include the older version of these frameworks? – Timothy Dec 06 '11 at 09:58
  • Hmm, that raises an interesting possibility. If you're only recently changed your app to include iOS 4.3 as your build target, try a clean build... – Duncan Babbage Dec 06 '11 at 10:02
  • amazing...don't know what to say then, i am stupid...please modify the answer and i will accept it. – Timothy Dec 06 '11 at 10:19
  • @Skyler As requested, I've updated my answer to include my recommendation in the comments that you try a clean build. :) – Duncan Babbage Dec 07 '11 at 06:25
3

Maybe you can try the code snippet below

[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&sessionError];
NSError * audio_session_err = nil;
[audio_session setCategory: AVAudioSessionCategoryPlayAndRecord error:&audio_session_err];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&audio_session_err];
[[AVAudioSession sharedInstance] setDelegate:self];
NSLog(@"!");

UInt32 audioRouteOverride = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,sizeof (audioRouteOverride),&audioRouteOverride);
UInt32 allowMixing = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);    

if (audio_session_err) {
  NSLog(@"audioSession: %@ %d %@", [audio_session_err domain], [audio_session_err code], [audio_session_err description]);
} else {
  audio_session_err = nil;
  [[AVAudioSession sharedInstance] setActive:YES error:&audio_session_err];
  if (!audio_session_err) NSLog(@"audio session is activated successfully");
}

I think audio_session = [[AVAudioSession sharedInstance] retain]; dispatchs the method setMode: by default. And the setMode: is only available in iOS 5.0 and later(refer to the Doc).

Or you can try to comment out the code:

UInt32 audioRouteOverride = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker,sizeof (audioRouteOverride),&audioRouteOverride);
UInt32 allowMixing = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(allowMixing), &allowMixing);

There must be a method dispatches the setMode: by default. Try yourself. :p


Try info malloc 0x706a7f0 in your gdb to get the object that the selector was sent to. Note, the 0x706a7f0 is the address that shown in your crash output as the one in your first code snippet.

And another tip, you might do make clean(Poduct->Clean) and rebuild it.

Kjuly
  • 34,476
  • 22
  • 104
  • 118
  • @Skyler Maybe you should not retain the `[AVAudioSession sharedInstance]`. Look [`HERE`](http://stackoverflow.com/questions/1010343/how-do-i-record-audio-on-iphone-with-avaudiorecorder) ;) – Kjuly Dec 06 '11 at 09:27
  • thank you:-) I have tried not to retain it, but it crashed all the same. – Timothy Dec 06 '11 at 09:33
  • I tried your snippet and also comment out the C code just now. it crashes with the same error :-( – Timothy Dec 06 '11 at 09:36
  • 2
    Hi @Skyler, I saw you have add some NSLog in your code. Can you show what have been print before the app crashed? – Kjuly Dec 06 '11 at 10:00
  • Thank you @Kjuly, the target output nothing before crash. It looks like crashed before runtime because I have a couple of NSLog in the `AppicationDidFinishLaunching`, but still nothing output. besides, the debugger output A LOT OF warning about 'more recent than executable timestamp' or 'Could not open OSO file to scan for pubtypes for objfile' – Timothy Dec 06 '11 at 10:08
  • @Skyler try `info malloc 0x706a7f0` in your gdb to get the object that the selector was sent to. Note, the `0x706a7f0` is the address that shown in your crash output as the one in your first code snippet. And another tip, you might do `make clean`(Poduct->Clean) and rebuild it. – Kjuly Dec 06 '11 at 10:19
1

The AVAudioSession method

- (BOOL)setMode:(NSString *)theMode error:(NSError **)outError

Is marked in the documentation as being available only for iOS 5 and later. In fact given the recent addition of modes to the documentation, it looks like audio session modes are not available at all prior to iOS 5.

jbat100
  • 16,757
  • 4
  • 45
  • 70
  • You could try a symbolic break point to work out where it's being called from in your code. – jbat100 Dec 06 '11 at 09:21
  • I added a symbolic break point to `-[AVAudioSession setMode:error:]` but nothing changed.it crashes as before. – Timothy Dec 06 '11 at 09:54
  • 1
    The symbolic break point wasn't intended to stop the crash, but rather to clarify the exact line in _your_ code that was leading to that method being called. :) – Duncan Babbage Dec 06 '11 at 10:03
  • hmm...indeed it clarified nothing. it looks like crashed before runtime. I added some NSLog in the `ApplicationDidFinishLaunching` but nothing output. – Timothy Dec 06 '11 at 10:12