How do you convert an iPhone OSStatus code to something useful?
I am getting more than a little sick of this iPhone SDK and its documentation...
I am calling AudioConverterNew
in the documentation under Returns: it says "returns a status code" ... really...
so far, through playing around with the parameters I have only been able to get two different errors neither of which are listed at the bottom of the Audio Converter reference.
they are 'mrep' and '?tmf' (casting the OSStatus to a char array) but the specific codes aren't really the point.
as far as I can tell, random error codes are defined in random files, so you can't just search one file, I can't find a help document that just lets you search for an error code to get more info, and from what I can tell, in OS X you can use GetMacOSStatusErrorString() to convert an error to something useful, but there is no iPhone equivalent?
any help would be greatly appreciated.
EDIT:
ok, so casting them gives them in reverse (something I checked for 'mrep' but was not there either way round) , fmt? is in the list for the Audio Converter api, and is pretty self explanatory if a bit vague, but fair enough, still 'perm' isn't there (although it might be something to do with the simulator 开发者_如何学JAVAnot supporting aac decoding) and my general question still stands.
OSStatus is a signed integer value. You cannot convert or "cast" it to a string. You can convert it to a NSError like this:
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
No. Not completely.
Some OSStatus are four-character-codes, so you can use (extracted from iPhone SDK's sample code "CAXException.h
")
static char *FormatError(char *str, OSStatus error)
{
// see if it appears to be a 4-char-code
*(UInt32 *)(str + 1) = CFSwapInt32HostToBig(error);
if (isprint(str[1]) && isprint(str[2]) && isprint(str[3]) && isprint(str[4])) {
str[0] = str[5] = '\'';
str[6] = '\0';
} else {
// no, format it as an integer
sprintf(str, "%d", (int)error);
}
return str;
}
(See iOS/C: Convert "integer" into four character string for some more ways to convert fourcc into string, including Swift)
NSError's NSOSStatusErrorDomain is able to decode some OS errors. See @tomk's answer.
If you don't need to decode the number in program for the user, you may use the macerror
script to manually find out the meaning, as mentioned in @lros's answer. The list of OSStatus supported can be found from its source code in /System/Library/Perl/Extras/5.18/Mac/Errors.pm
.
There is also an online service http://osstatus.com/ collecting errors from all public frameworks. They are still not really complete e.g. the mapping to -12792
mentioned in the comment is missing. Probably it is a code from a private framework.
This is available on macOS and for iOS from 11.3 and above.
I know this is an old post, but I was reading the apple docs in a section related to keychains. They mention a method that is used to convert OSStatus errors into something readable.
SecCopyErrorMessageString
Returns a string explaining the meaning of a security result code.
SecCopyErrorMessageString (OSStatus status, void* reserved );
Useage:
NSString* ErrMsg = (__bridge_transfer NSString *) SecCopyErrorMessageString(theOSStatusError, NULL);
It worked for me with my keychain OSStatus errors. Does it work for you? You will need Security.Framework added to your project to use this method.
I recently ran across another approach: the macerror command. Print out the OSStatus value as a signed integer. Then in a terminal window (on your Mac, not your iDevice!) type for example macerror -50. It will respond with a brief description. Obviously this is only helpful for you, during development.
Here is the code I wrote, hope it save you some typing... er, don't know how to make it show up correctly.
- (NSString *)OSStatusToStr:(OSStatus)st
{
switch (st) {
case kAudioFileUnspecifiedError:
return @"kAudioFileUnspecifiedError";
case kAudioFileUnsupportedFileTypeError:
return @"kAudioFileUnsupportedFileTypeError";
case kAudioFileUnsupportedDataFormatError:
return @"kAudioFileUnsupportedDataFormatError";
case kAudioFileUnsupportedPropertyError:
return @"kAudioFileUnsupportedPropertyError";
case kAudioFileBadPropertySizeError:
return @"kAudioFileBadPropertySizeError";
case kAudioFilePermissionsError:
return @"kAudioFilePermissionsError";
case kAudioFileNotOptimizedError:
return @"kAudioFileNotOptimizedError";
case kAudioFileInvalidChunkError:
return @"kAudioFileInvalidChunkError";
case kAudioFileDoesNotAllow64BitDataSizeError:
return @"kAudioFileDoesNotAllow64BitDataSizeError";
case kAudioFileInvalidPacketOffsetError:
return @"kAudioFileInvalidPacketOffsetError";
case kAudioFileInvalidFileError:
return @"kAudioFileInvalidFileError";
case kAudioFileOperationNotSupportedError:
return @"kAudioFileOperationNotSupportedError";
case kAudioFileNotOpenError:
return @"kAudioFileNotOpenError";
case kAudioFileEndOfFileError:
return @"kAudioFileEndOfFileError";
case kAudioFilePositionError:
return @"kAudioFilePositionError";
case kAudioFileFileNotFoundError:
return @"kAudioFileFileNotFoundError";
default:
return @"unknown error";
}
}
I recently found this really nice website that's worked for every status value I've thrown at it. It's a lot more user friendly than grepping through the framework header files: http://www.osstatus.com/
I combined a few answers. Actually I were looking something like „throw errorForStatusCode(status)”. But in the end achieved:
guard status == errSecSuccess else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(status), userInfo: [NSLocalizedDescriptionKey: SecCopyErrorMessageString(status, nil) ?? "Undefined error"])
}
SecCopyErrorMessageString is available from iOS 11.3 https://developer.apple.com/documentation/security/1542001-security_framework_result_codes
For iOS 11.3+, I'm using an extension on OSStatus
…
extension OSStatus {
var error: NSError? {
guard self != errSecSuccess else { return nil }
let message = SecCopyErrorMessageString(self, nil) as String? ?? "Unknown error"
return NSError(domain: NSOSStatusErrorDomain, code: Int(self), userInfo: [
NSLocalizedDescriptionKey: message])
}
}
which you can call like…
let status = SecItemAdd(attributes as CFDictionary, nil)
if let error = status.error {
throw error
}
// etc
Having written this I noticed this is very close to @RomanMykitchak's earlier answer (so please give him the upvote) - but I'll leave it here as the extension might prove useful to someone.
I created an OSStatus extension that you may find useful. It logs a full error message for audio related errors, otherwise when possible the four-character-code, otherwise the OSStatus number that you could look-up in https://www.osstatus.com
It furthers adds useful information like the file, the function and the line where the error occurred.
Here is the code:
let isDebug = true
//**************************
// OSStatus extensions for logging
//**************************
extension OSStatus {
//**************************
func asString() -> String? {
let n = UInt32(bitPattern: self.littleEndian)
guard let n1 = UnicodeScalar((n >> 24) & 255), n1.isASCII else { return nil }
guard let n2 = UnicodeScalar((n >> 16) & 255), n2.isASCII else { return nil }
guard let n3 = UnicodeScalar((n >> 8) & 255), n3.isASCII else { return nil }
guard let n4 = UnicodeScalar( n & 255), n4.isASCII else { return nil }
return String(n1) + String(n2) + String(n3) + String(n4)
} // asString
//**************************
func detailedErrorMessage() -> String? {
switch(self) {
//***** AUGraph errors
case kAUGraphErr_NodeNotFound: return "AUGraph Node Not Found"
case kAUGraphErr_InvalidConnection: return "AUGraph Invalid Connection"
case kAUGraphErr_OutputNodeErr: return "AUGraph Output Node Error"
case kAUGraphErr_CannotDoInCurrentContext: return "AUGraph Cannot Do In Current Context"
case kAUGraphErr_InvalidAudioUnit: return "AUGraph Invalid Audio Unit"
//***** MIDI errors
case kMIDIInvalidClient: return "MIDI Invalid Client"
case kMIDIInvalidPort: return "MIDI Invalid Port"
case kMIDIWrongEndpointType: return "MIDI Wrong Endpoint Type"
case kMIDINoConnection: return "MIDI No Connection"
case kMIDIUnknownEndpoint: return "MIDI Unknown Endpoint"
case kMIDIUnknownProperty: return "MIDI Unknown Property"
case kMIDIWrongPropertyType: return "MIDI Wrong Property Type"
case kMIDINoCurrentSetup: return "MIDI No Current Setup"
case kMIDIMessageSendErr: return "MIDI Message Send Error"
case kMIDIServerStartErr: return "MIDI Server Start Error"
case kMIDISetupFormatErr: return "MIDI Setup Format Error"
case kMIDIWrongThread: return "MIDI Wrong Thread"
case kMIDIObjectNotFound: return "MIDI Object Not Found"
case kMIDIIDNotUnique: return "MIDI ID Not Unique"
case kMIDINotPermitted: return "MIDI Not Permitted"
//***** AudioToolbox errors
case kAudioToolboxErr_CannotDoInCurrentContext: return "AudioToolbox Cannot Do In Current Context"
case kAudioToolboxErr_EndOfTrack: return "AudioToolbox End Of Track"
case kAudioToolboxErr_IllegalTrackDestination: return "AudioToolbox Illegal Track Destination"
case kAudioToolboxErr_InvalidEventType: return "AudioToolbox Invalid Event Type"
case kAudioToolboxErr_InvalidPlayerState: return "AudioToolbox Invalid Player State"
case kAudioToolboxErr_InvalidSequenceType: return "AudioToolbox Invalid Sequence Type"
case kAudioToolboxErr_NoSequence: return "AudioToolbox No Sequence"
case kAudioToolboxErr_StartOfTrack: return "AudioToolbox Start Of Track"
case kAudioToolboxErr_TrackIndexError: return "AudioToolbox Track Index Error"
case kAudioToolboxErr_TrackNotFound: return "AudioToolbox Track Not Found"
case kAudioToolboxError_NoTrackDestination: return "AudioToolbox No Track Destination"
//***** AudioUnit errors
case kAudioUnitErr_CannotDoInCurrentContext: return "AudioUnit Cannot Do In Current Context"
case kAudioUnitErr_FailedInitialization: return "AudioUnit Failed Initialization"
case kAudioUnitErr_FileNotSpecified: return "AudioUnit File Not Specified"
case kAudioUnitErr_FormatNotSupported: return "AudioUnit Format Not Supported"
case kAudioUnitErr_IllegalInstrument: return "AudioUnit Illegal Instrument"
case kAudioUnitErr_Initialized: return "AudioUnit Initialized"
case kAudioUnitErr_InvalidElement: return "AudioUnit Invalid Element"
case kAudioUnitErr_InvalidFile: return "AudioUnit Invalid File"
case kAudioUnitErr_InvalidOfflineRender: return "AudioUnit Invalid Offline Render"
case kAudioUnitErr_InvalidParameter: return "AudioUnit Invalid Parameter"
case kAudioUnitErr_InvalidProperty: return "AudioUnit Invalid Property"
case kAudioUnitErr_InvalidPropertyValue: return "AudioUnit Invalid Property Value"
case kAudioUnitErr_InvalidScope: return "AudioUnit InvalidScope"
case kAudioUnitErr_InstrumentTypeNotFound: return "AudioUnit Instrument Type Not Found"
case kAudioUnitErr_NoConnection: return "AudioUnit No Connection"
case kAudioUnitErr_PropertyNotInUse: return "AudioUnit Property Not In Use"
case kAudioUnitErr_PropertyNotWritable: return "AudioUnit Property Not Writable"
case kAudioUnitErr_TooManyFramesToProcess: return "AudioUnit Too Many Frames To Process"
case kAudioUnitErr_Unauthorized: return "AudioUnit Unauthorized"
case kAudioUnitErr_Uninitialized: return "AudioUnit Uninitialized"
case kAudioUnitErr_UnknownFileType: return "AudioUnit Unknown File Type"
case kAudioUnitErr_RenderTimeout: return "AudioUnit Rendre Timeout"
//***** AudioComponent errors
case kAudioComponentErr_DuplicateDescription: return "AudioComponent Duplicate Description"
case kAudioComponentErr_InitializationTimedOut: return "AudioComponent Initialization Timed Out"
case kAudioComponentErr_InstanceInvalidated: return "AudioComponent Instance Invalidated"
case kAudioComponentErr_InvalidFormat: return "AudioComponent Invalid Format"
case kAudioComponentErr_NotPermitted: return "AudioComponent Not Permitted "
case kAudioComponentErr_TooManyInstances: return "AudioComponent Too Many Instances"
case kAudioComponentErr_UnsupportedType: return "AudioComponent Unsupported Type"
//***** Audio errors
case kAudio_BadFilePathError: return "Audio Bad File Path Error"
case kAudio_FileNotFoundError: return "Audio File Not Found Error"
case kAudio_FilePermissionError: return "Audio File Permission Error"
case kAudio_MemFullError: return "Audio Mem Full Error"
case kAudio_ParamError: return "Audio Param Error"
case kAudio_TooManyFilesOpenError: return "Audio Too Many Files Open Error"
case kAudio_UnimplementedError: return "Audio Unimplemented Error"
default: return nil
} // switch(self)
} // detailedErrorMessage
//**************************
func debugLog(filePath: String = #file, line: Int = #line, funcName: String = #function) {
guard isDebug, self != noErr else { return }
let fileComponents = filePath.components(separatedBy: "/")
let fileName = fileComponents.last ?? "???"
var logString = "OSStatus = \(self) in \(fileName) - \(funcName), line \(line)"
if let errorMessage = self.detailedErrorMessage() { logString = errorMessage + ", " + logString }
else if let errorCode = self.asString() { logString = errorCode + ", " + logString }
NSLog(logString)
} // debugLog
} // extension OSStatus
And usage would be:
//***** Create audioGraph
NewAUGraph(&audioGraph).debugLog()
//***** Testing .debugLog() OSStatus extension
kAUGraphErr_InvalidAudioUnit.debugLog()
OSStatus(560226676).debugLog()
OSStatus(-125).debugLog()
The resulting logs for the three tests:
2018-11-12 19:41:48.427606+0100 HexaSynth[5875:102611] AUGraph Invalid Audio Unit, OSStatus = -10864 in SoftSynthesizer.swift - init(soundFontFileName:), line 40
2018-11-12 19:41:48.428403+0100 HexaSynth[5875:102611] !dat, OSStatus = 560226676 in SoftSynthesizer.swift - init(soundFontFileName:), line 41
2018-11-12 19:41:48.428638+0100 HexaSynth[5875:102611] OSStatus = -125 in SoftSynthesizer.swift - init(soundFontFileName:), line 42
Use the OSX calc program. Select "programmer" mode in presentation menu. Then type your code in decimal représentation. Then choose the "ascii" button and the calc will show you the 4 char translation such as "!init", "!cat", etc...
Failing a description string, it's convenient to convert OSStatus values to strings that look like their four-character definitions. At least then you can grep headers in hopes of finding a comment about what the status means.
// declaration: extern CFStringRef CreateTypeStringWithOSType(OSType inType);
OSStatus result = ...;
if (result != noErr) {
NSString *statusString = (NSString *)CreateTypeStringWithOSType(result);
NSLog(@"Error while $VERBing: %@", statusString);
[statusString release]; // because "Create..."
statusString = nil;
}
Most time maybe you just need to find the error code in the .h files
I just made a python script to find the code (when you debug/print a osstatus code)
https://github.com/sprhawk/MyGist/blob/master/tools/find_osstatus_error.py
If you want to create a command line utility, for use during development and support, then you can still use the deprecated Carbon methods, even in 10.9 (Mavericks). You obviously can't use this in an app you are submitting to Apple for inclusion in the App Stores.
#import <Foundation/Foundation.h>
#import <CoreServices/CoreServices.h>
int main(int argc, const char **argv)
{
@autoreleasepool {
for (int i = 1; i < argc; i++) {
char *endp;
long value = strtol(argv[i], &endp, 10);
if (*endp == '\0') {
printf("%10ld: %s (%s)\n",
value,
GetMacOSStatusCommentString((OSStatus)value),
GetMacOSStatusErrorString((OSStatus)value));
} else {
fprintf(stderr, "Invalid OSStatus code '%s' ignored\n", argv[i]);
}
}
}
}
Compile with:
$ clang -fobjc-arc -o osstatus osstatus.m -framework Foundation -framework CoreServices
copy it somewhere in your $PATH
:
$ cp osstatus ~/bin
and feed it error codes from your log files or error reports:
$ osstatus -47
-47: File is busy (delete) (fBsyErr)
This is not a direct answer to OP's question, but I think it will be useful to whoever is concerned with these OSStatus return codes:
Search for keyword "Result Codes" in Xcode documentation (Organizer) and we get a more or less categorized return codes documentation sections in the "System Guides" result.
If you just need to use some codes directly in your custom functions, they are very helpful.
OSStatus errors can be bytes representing a 4-char code, or any number of errors defined in MacErrors.h
.
If an OSStatus error is 0
or noErr
that means you have no error.
Or, try looking up your error number in MacErrors.h
:
http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/MacErrors.h
This might be help.
static NSString *stringForOSStatus(OSStatus status)
{
NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.apple.security"];
NSString *key = [NSString stringWithFormat:@"%d", status];
return [bundle localizedStringForKey:key value:key table:@"SecErrorMessages"];
}
for Security framework on IOS given that SecCopyErrorMessageString is missing on the platform it's DYI
add error codes at the bottom of
https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices
to your very own switch.
for example
let status : OSStatus = SecItemAdd(query as CFDictionaryRef, nil)
switch status {
case errSecSuccess:
return nil
case errSecAuthFailed:
// that's the result of dumping kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly into the query
return "changing app lock type on a device without fingerprint and/or passcode setup is not allowed".localized
default:
return "unhandled case: implement this"
}
This is what you need https://www.osstatus.com/. Just search for given OSStatus.
OSStatus err; ... printf("%s", (char*)&err);
精彩评论