【问题标题】:Swift 4, reading byte dataSwift 4,读取字节数据
【发布时间】:2018-09-19 05:37:06
【问题描述】:

所以我最近更新了我的 IMAC 和 Xcode,在更新后我的部分代码没有按预期运行。这是我最初检查消息的地方。

func checkForMessages() {
    while true {
        if inputBuffer.length < 4 {
            return
        }
        var msgLength = (inputBuffer.bytes).load(as: UInt32.self)
        msgLength = UInt32(bigEndian: msgLength)
        print("msgLength = \(msgLength)")
        print("inputBuffer Length = \(inputBuffer.length)")
        print("inputBuffer = \(inputBuffer)")
        if inputBuffer.length < msgLength {
            return
        }
        //print("data = \(inputBuffer.subdata(with: NSRange(location: 4, length: Int(msgLength))))")
        if inputBuffer.length < msgLength + 4 {
            return
        }
        let message: Data? = inputBuffer.subdata(with: NSRange(location: 4, length: Int(msgLength)))
        processMessage(message!)
        let amtRemaining: Int = inputBuffer.length - Int(msgLength) - 4
        if amtRemaining == 0 {
            inputBuffer = NSMutableData()
        }
        else {
            print("Creating input buffer of length \(amtRemaining)")
            inputBuffer = NSMutableData(bytes: inputBuffer.bytes + 4 + Int(msgLength), length: amtRemaining)
        }
    }
}

然后是进程消息函数

func processMessage(_ data: Data) {

    let reader = MessageReader(data: data)
    print("this is the message data\(data)")
    let msgType  = reader?.readByte().hashValue
}

然后是真正的 MessageReader,它位于 Objective C,因为我不久前将它从互联网上撤下。从那以后它对我来说一直很好。到现在为止。

#import "MessageReader.h"

@implementation MessageReader

- (id)initWithData:(NSData *)data {
   if ((self = [super init])) {
      _data = data;
      _offset = 0;
}
return self;
}

- (unsigned char)readByte {
    unsigned char retval = *((unsigned char *) (_data.bytes + _offset));
    _offset += sizeof(unsigned char);
    return retval;
}

- (int)readInt {
    int retval = *((unsigned int *) (_data.bytes + _offset));
   retval = ntohl(retval);
   _offset += sizeof(unsigned int);
   return retval;
}

- (NSString *)readString {
   int strLen = [self readInt];
   NSString *retval = [NSString stringWithCString:_data.bytes + _offset encoding:NSUTF8StringEncoding];
   _offset += strLen;
   return retval;
}

- (void)dealloc {
}

@end

现在的问题是,它没有返回“1”或“2”、“30”等数字,而是返回了一些像 1836718193728 这样的巨大数字。我相信问题在于 messageReader、readByte 函数。

【问题讨论】:

  • "我的部分代码没有按预期运行" 现在会发生什么?怎么了?
  • 对不起,我以为我添加了正在发生的事情,所以我一直在调试整个代码。并发现错误发生在readByte,例如。服务器发送值“1”,然后当从 UInt8 转换为 Int 时,最终得到的值类似于“1837619902737”而不是“1”,这些数字不是直接的,但同样的概念适用。
  • 所以 reader?.readByte().hasValue 返回一个巨大的数字,而不是像“1”或“20”等。
  • 您能否使用该信息更新您的问题(比在 cmets 中更明显)?还有,难道它不再是 BigEndian 了吗?

标签: objective-c swift4 inputstream outputstream


【解决方案1】:

根据您的评论,reader?.readByte().hasValue 正在返回一个巨大的数字。 (我相信 hasValue 只是一个错字,它的 hashValue。)

这是hashValue 的可能行为。

您是否将hashValue 用作UInt8Int 的转换工具?

这是错误的。属性hashValue 已(并且应该)实现返回一些满足一个公理的Int 值:

where a == b, a.hashValue == b.hashValue

在旧版本的 Swift 中,UInt8.hashValue 可能返回了相同类型的 Int 值,但您不应依赖未记录的此类实现细节。实现的细微变化会导致不同的结果。

事实上,Swift 4.2 已经彻底改变了hashValue 的实现。

SE-0206 Hashable Enhancements

您可能需要使用hashValue 修复项目的所有部分。 通常,您使用Int.init(_:)UInt8 转换为Int

let msgType 中显示的可选链接等上下文中,您可能需要编写类似的内容。

    let msgType = (reader?.getByte()).map{Int($0)}

如果你有很多部分错误地使用了hashValue,最好写一个扩展:

extension UInt8 {
    var integerValue: Int {
        return Int(self)
    }
}

    let msgType = reader?.getByte().integerValue

通常,您最好不要在项目中包含此类错误的 hack。

【讨论】:

    猜你喜欢
    • 2015-04-24
    • 2018-06-28
    • 2018-10-31
    • 1970-01-01
    • 1970-01-01
    • 2021-07-16
    • 1970-01-01
    • 2015-10-25
    • 2015-04-02
    相关资源
    最近更新 更多