这可能是一个老问题,但由于它是在 Core Audio 的背景下提出的,所以我只想分享一个我正在玩的变体。
对于 Core Audio,其中一些(但不是全部?)OSStatus/Int32 值是使用四个字符定义的,Apple 旧的 Core Audio 实用程序类中的一些代码可以提供灵感(非常类似于 linked question)
来自CAXException.h:
class CAX4CCStringNoQuote {
public:
CAX4CCStringNoQuote(OSStatus error) {
// see if it appears to be a 4-char-code
UInt32 beErr = CFSwapInt32HostToBig(error);
char *str = mStr;
memcpy(str, &beErr, 4);
if (isprint(str[0]) && isprint(str[1]) && isprint(str[2]) && isprint(str[3])) {
str[4] = '\0';
} else if (error > -200000 && error < 200000)
// no, format it as an integer
snprintf(str, sizeof(mStr), "%d", (int)error);
else
snprintf(str, sizeof(mStr), "0x%x", (int)error);
}
const char *get() const { return mStr; }
operator const char *() const { return mStr; }
private:
char mStr[16];
};
在 Swift 5 中,一种粗略的翻译(没有大值的十六进制表示)可能是:
private func osStatusToString(_ value: OSStatus) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value)
}
}
请注意,Data 初始化程序正在复制字节,但如果需要,可以避免这种情况。
当然,对于 Core Audio,我们会遇到 both Int32 和 UInt32 类型的四个字符代码。我之前没有使用 Swift 完成泛型,但是在单个函数中处理它们的一种方法可能是:
private func stringifyErrorCode<T: FixedWidthInteger>(_ value: T) -> String {
let data = withUnsafeBytes(of: value.bigEndian, { Data($0) })
// If all bytes are printable characters, we treat it like characters of a string
if data.allSatisfy({ 0x20 <= $0 && $0 <= 0x7e }) {
return String(data: data, encoding: .ascii)!
} else {
return String(value, radix: 10)
}
}
这可能不适合四个字符代码的通用处理(我在上面的示例中看到了支持 MacOS 罗马编码与 ASCII 字符的其他答案。可能有一些我不知道的历史) ,但对于 Core Audio 状态/选择器代码可能是合理的。