【问题标题】:How do you convert an iPhone OSStatus code to something useful?如何将 iPhone OSStatus 代码转换为有用的东西?
【发布时间】:2011-01-12 21:40:40
【问题描述】:

我对这个 iPhone SDK 及其文档感到有点厌烦...

我正在调用 AudioConverterNew

在 Returns 下的文档中:它说“返回状态代码” ... 真的……

到目前为止,通过调整参数,我只能得到两个不同的错误,这两个错误都没有在音频转换器参考的底部列出。

它们是 'mrep' 和 '?tmf'(将 OSStatus 转换为 char 数组),但具体代码并不是重点。

据我所知,随机错误代码是在随机文件中定义的,因此您不能只搜索一个文件,我找不到只能让您搜索错误代码以获取更多信息的帮助文档,据我所知,在 OS X 中,您可以使用 GetMacOSStatusErrorString() 将错误转换为有用的东西,但没有 iPhone 等效项?

任何帮助将不胜感激。

编辑:

好的,所以投射它们会使它们反过来(我检查了'mrep'但没有任何一种方式),fmt?位于音频转换器 api 的列表中,如果有点含糊,则可以自我解释,但足够公平,仍然不存在“烫发”(尽管它可能与不支持 aac 解码的模拟器有关)和我的一般问题仍然存在。

【问题讨论】:

  • @matt 你在 swift 中找到解决方案了吗?顺便说一句,很好的问题

标签: ios macos cocoa-touch cocoa error-handling


【解决方案1】:

OSStatus 是一个有符号整数值。您不能将其转换或“转换”为字符串。您可以像这样将其转换为 NSError:

NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];

【讨论】:

  • 这个问题很老,但我会说这是正确的答案。然后,您可以获得一个描述性字符串,例如2012-11-05 22:28:52.338 foo[7300:707] Error Domain=NSOSStatusErrorDomain Code=-43 "The operation couldn’t be completed. (OSStatus error -43.)" (fnfErr: File not found)
  • 对于这种方式的许多错误,除了“操作无法完成”之外,您无法获得任何信息。这个答案和公认的答案相结合效果很好。
  • 在swift中它没有提供与代码-12792相关的任何内容,我也尝试过其他一些代码但没有..
  • 这个答案很有用,但错误文档不佳的潜在问题仍然是一个问题。访问 OSStatus 查找站点就可以了,但这是 Apple 的失误。
  • "您不能将其转换或“转换”为字符串" ...您知道 Apple 的许多文件格式和 API 使用“4CC”,即 4 个 ASCII 字符的序列转换为通过以大端顺序连接它们的整数? (4CC 也用于各种媒体文件格式,因此已进入非 Apple OS 媒体库,例如 Windows DirectShow 使用它们来识别编解码器)。这意味着将它们转换为字符串以进行显示实际上是非常明智的做法。
【解决方案2】:

没有。不完全。

有些OSStatus是四字符码,所以你可以使用(摘自iPhone SDK的示例代码“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;
}

(见iOS/C: Convert "integer" into four character string更多将fourcc转换成字符串的方法,包括Swift)

NSError 的 NSOSStatusErrorDomain 能够解码一些操作系统错误。见@tomk's answer

如果您不需要为用户解码程序中的数字,您可以使用macerror脚本手动查找含义,如@lros's answer中所述。可以从/System/Library/Perl/Extras/5.18/Mac/Errors.pm 的源代码中找到支持的 OSStatus 列表。

还有一个在线服务http://osstatus.com/ 从所有公共框架收集错误。它们仍然不完整,例如缺少注释中提到的到-12792 的映射。可能是来自私有框架的代码。

【讨论】:

  • 这会在 if 条件行上生成编译器警告:“函数调用参数是未初始化的值”
  • 你不觉得吗,如果发明 OSStatus 的开发者希望它是一个字符串,他会将它声明为一个而不是一个有符号整数?您不能或至少不应将整数“转换”为字符串。
  • @tomk: (1) 你知道这段代码来自the official Apple sample codes吗? (2) 您如何确定发明 OSStatus 的开发人员不想使用 4 个字节作为存储 4 个字符的紧凑方式?我确定 this 是真的,因为 OSType 源自 Mac OS。
  • 我不得不承认,我是后来才发现的。但正如您所写,“......一些 OSStatus 是四个......”。 “mrep”和“?tmf”听起来不像是正确的错误代码。请参阅我对 public 函数将 OSStatus 转换为错误字符串的答案。
  • @tomk:那是因为你是倒着读的。它们是permperm-ission 错误)和fmt?(错误f-or-m-a-t )。您的公共方法是否显示“权限错误”和“格式错误”或仅显示“操作无法完成。”?顺便说一句,这个答案中的方法也是公开的,只是它不是在一行中完成的。
【解决方案3】:

这适用于 macOS 和 11.3 及更高版本的 iOS。

我知道这是一篇旧帖子,但我在与钥匙串相关的部分阅读the apple docs。他们提到了一种用于将 OSStatus 错误转换为可读内容的方法。

SecCopyErrorMessageString

返回解释安全结果代码含义的字符串。

SecCopyErrorMessageString (OSStatus 状态, void* reserved );

用途:

NSString* ErrMsg = (__bridge_transfer NSString *) SecCopyErrorMessageString(theOSStatusError, NULL);

它适用于我的钥匙串 OSStatus 错误。对你起作用吗?您需要将Security.Framework 添加到您的项目中才能使用此方法。

【讨论】:

  • 很遗憾,SecCopyErrorMessageString 在 iOS 上不存在。
  • 明白了。我会留下这个,以防它对 Mac 上的人有帮助
  • 不幸的是,它不适用于所有 OSStatus。例如,它无法使用 Core Audio OSStatus 打印错误
  • 谢谢。这是快速的语法: if let error: CFString = SecCopyErrorMessageString(status, nil) {
  • iOS 11.3 及以上版本包含。
【解决方案4】:

我最近遇到了另一种方法:macerror 命令。将 OSStatus 值打印为有符号整数。然后在终端窗口中(在您的 Mac 上,而不是您的 iDevice!)输入例如 ma​​cerror -50。它将以简短的描述作为回应。显然,这只会在开发过程中对您有所帮助。

【讨论】:

  • 这似乎为绝大多数错误代码返回“未知错误代码”
【解决方案5】:

这是我写的代码,希望它可以节省你的打字时间……呃,不知道如何让它正确显示。

- (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";
    }
}

【讨论】:

  • 使用宏和字符串化并节省更多的输入。
  • 这很有帮助,不过您应该为0 添加一个案例,这意味着没有错误。
【解决方案6】:

我最近发现了这个非常棒的网站,它适用于我所投入的每个状态值。这比通过框架头文件搜索要友好得多:http://www.osstatus.com/

【讨论】:

  • 它无法理解 -34018
【解决方案7】:

我结合了几个答案。实际上,我正在寻找类似“throw errorForStatusCode(status)”的东西。 但最终实现了:

    guard status == errSecSuccess else {
        throw  NSError(domain: NSOSStatusErrorDomain, code: Int(status), userInfo: [NSLocalizedDescriptionKey: SecCopyErrorMessageString(status, nil) ?? "Undefined error"])
    }

SecCopyErrorMessageString 从 iOS 11.3 开始可用 https://developer.apple.com/documentation/security/1542001-security_framework_result_codes

【讨论】:

  • iOS 11.3 及更高版本的绝佳答案
【解决方案8】:

对于 iOS 11.3+,我在 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])
    }
}

你可以这样称呼……

let status = SecItemAdd(attributes as CFDictionary, nil)

if let error = status.error {
    throw error
}    
// etc

写完这篇文章后,我注意到这与 @RomanMykitchak 之前的回答非常接近(所以请给他点赞)——但我将把它留在这里,因为扩展可能对某人有用。

【讨论】:

    【解决方案9】:

    我创建了一个您可能会觉得有用的 OSStatus 扩展。它会记录音频相关错误的完整错误消息,否则可能会记录四字符代码,否则会记录您可以在https://www.osstatus.com 中查找的 OSStatus 编号

    它进一步添加了有用的信息,如文件、函数和发生错误的行。

    代码如下:

    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
    

    用法如下:

    //***** Create audioGraph
    NewAUGraph(&audioGraph).debugLog()
    
    //***** Testing .debugLog() OSStatus extension
    kAUGraphErr_InvalidAudioUnit.debugLog()
    OSStatus(560226676).debugLog()
    OSStatus(-125).debugLog()
    

    三个测试的结果日志:

    2018-11-12 19:41:48.427606+0100 HexaSynth[5875:102611] AUGraph 音频单元无效,SoftSynthesizer.swift 中的 OSStatus = -10864 - init(soundFontFileName:),第 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

    【讨论】:

    • 感谢您的回答。该代码正在运行,但我错过了与 AVAudioRecorder 相关的错误。我借用了您的代码并在此处添加了缺失的错误:stackoverflow.com/a/58348781/598057。您也可以在此处添加它们。
    • 很高兴这对您有用。当然,每个人都应该针对在他们的上下文中有用的错误调整代码。
    【解决方案10】:

    使用 OSX 计算程序。在演示菜单中选择“程序员”模式。 然后以十进制表示输入您的代码。然后选择“ascii”按钮,calc 会显示 4 个字符的翻译,例如“!init”、“!cat”等...

    【讨论】:

      【解决方案11】:

      如果描述字符串失败,可以方便地将 OSStatus 值转换为看起来像它们的四字符定义的字符串。至少你可以 grep 标题,希望能找到关于状态含义的评论。

      // 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;
      }
      

      【讨论】:

      • Swift 中CreateTypeStringWithOSType 的等价物是什么?我没有设法使用它...
      【解决方案12】:

      大多数时候你可能只需要在 .h 文件中找到错误代码

      我刚刚制作了一个 python 脚本来查找代码(当您调试/打印 osstatus 代码时)

      https://github.com/sprhawk/MyGist/blob/master/tools/find_osstatus_error.py

      【讨论】:

        【解决方案13】:

        如果您想创建一个命令行实用程序,以便在开发和支持期间使用,那么您仍然可以使用已弃用的 Carbon 方法,即使在 10.9(Mavericks)中也是如此。您显然不能在您提交给 Apple 以纳入 App Store 的应用中使用它。

        #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]);
                    }
                }
            }
        }
        

        编译:

        $ clang -fobjc-arc -o osstatus osstatus.m -framework Foundation -framework CoreServices
        

        将其复制到您的$PATH

        $ cp osstatus ~/bin
        

        并从您的日志文件或错误报告中提供错误代码:

        $ osstatus -47
           -47: File is busy (delete) (fBsyErr)
        

        【讨论】:

          【解决方案14】:

          这不是对 OP 问题的直接回答,但我认为这对关心这些 OSStatus 返回码的人很有用:

          在 Xcode 文档(Organizer)中搜索关键字“结果代码”,我们在“系统指南”结果中得到或多或少分类的返回代码文档部分。

          如果您只需要在自定义函数中直接使用一些代码,它们会非常有帮助。

          【讨论】:

            【解决方案15】:

            OSStatus 错误可以是表示 4 字符代码的字节,也可以是 MacErrors.h 中定义的任意数量的错误。

            如果 OSStatus 错误为 0noErr,则表示您没有错误。

            或者,尝试在MacErrors.h 中查找您的错误号:

            http://www.opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/MacErrors.h

            【讨论】:

              【解决方案16】:

              这可能会有所帮助。

              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"];
              }
              

              【讨论】:

              • 这在 iOS 9 上不起作用(我没有尝试任何其他版本)因为[NSBundle bundleWithIdentifier:@"com.apple.security"] 返回nil
              【解决方案17】:

              对于 IOS 上的安全框架,因为平台上缺少 SecCopyErrorMessageString,它是 DYI

              在底部添加错误代码

              https://developer.apple.com/library/ios/documentation/Security/Reference/keychainservices

              到您自己的开关。

              例如

                      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"
                      }
              

              【讨论】:

                【解决方案18】:

                这就是你需要的https://www.osstatus.com/。 只需搜索给定的 OSStatus。

                【讨论】:

                  【解决方案19】:

                  操作系统状态错误; ... printf("%s", (char*)&err);

                  【讨论】:

                  • 如果堆栈上很快没有 0 字节,这将导致很好的崩溃。
                  • 你会使用 printf("%d", err)。
                  • 即使 Jon Skeet 在地球上的存在也不足以让这个答案正确!
                  猜你喜欢
                  • 2015-09-29
                  • 1970-01-01
                  • 2021-10-24
                  • 1970-01-01
                  • 1970-01-01
                  • 2017-01-28
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多