【问题标题】:swift3 Date to Data, Data to Date convertswift3 日期转数据,数据转日期
【发布时间】:2017-12-18 00:48:38
【问题描述】:

我正在努力将在目标 c 中创建的代码更改为 swift3。
我想把下面的代码改成用objective c创建的swift3代码。

Objective c NSDate to NSData 代码:

NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [calendar components:NSDayCalendarUnit |NSMonthCalendarUnit | NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:[NSDate date]];

NSInteger year = components.year;
NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];
int month = components.month;
int day = components.day;
int hour = components.hour;
int min = components.minute;
int second = components.second;

char bytes[7];
bytes[0] = year1;
bytes[1] = year2;
bytes[2] = month;
bytes[3] = day;
bytes[4] = hour;
bytes[5] = min;
bytes[6] = second;
NSData *data = [[NSData alloc] initWithBytes:&bytes length:sizeof(bytes)];

Objective c NSData 到 NSDate 代码:

NSData *date = [[NSData alloc] initWithData:characteristic.value];
int year = *(int *)[[date subdataWithRange:NSMakeRange(0, 2)] bytes];
int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];
int day = *(int *)[[date subdataWithRange:NSMakeRange(3, 1)] bytes];
int hour = *(int *)[[date subdataWithRange:NSMakeRange(4, 1)] bytes];
int minutes = *(int *)[[date subdataWithRange:NSMakeRange(5, 1)] bytes];
int seconds = *(int *)[[date subdataWithRange:NSMakeRange(6, 1)] bytes];

NSLog(@"year %d month %d day %d hour %d minutes %d second %d", year, month, day, hour, minutes, seconds); //year 2017 month 7 day 13 hour 16 minutes 8 second 2

NSDateComponents *components = [[NSDateComponents alloc] init];
[components setYear:year];
[components setMonth:month];
[components setDay:day];
[components setHour:hour];
[components setMinute:minutes];
[components setSecond:seconds];
NSCalendar *calendar = [NSCalendar currentCalendar];
self.time = [calendar dateFromComponents:components];

Swift 日期转数据代码:

let cal = Calendar(identifier: .gregorian)
var comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: Date())
var year = comp.year
let yearData:Data = Data(bytes: &year, count: MemoryLayout.size(ofValue: year))
let year1:Data = yearData.subdata(in: 0..<1)
let year2:Data = yearData.subdata(in: 1..<2)
let settingArray = [UInt8]([
      UInt8(year1[0])
    , UInt8(year2[0])
    , UInt8(comp.month!)
    , UInt8(comp.day!)
    , UInt8(comp.hour!)
    , UInt8(comp.minute!)
    , UInt8(comp.second!)
])
let settingData:Data = Data(bytes: settingArray, count: MemoryLayout.size(ofValue: settingArray))

Swift 数据到日期代码:

var yearVal:UInt8 = 0
let year = characteristic.value?.subdata(in: 0..<2)
year?.copyBytes(to: &yearVal, count: MemoryLayout.size(ofValue: year))
var month = characteristic.value?.subdata(in: 2..<3)
var day = characteristic.value?.subdata(in: 3..<4)
var hour = characteristic.value?.subdata(in: 4..<5)
var minutes = characteristic.value?.subdata(in: 5..<6)
var seconds = characteristic.value?.subdata(in: 6..<7)
print("year = \(yearVal), month = \(Int((month?[0])!)), day = \(Int((day?[0])!)), hour = \(Int((hour?[0])!)), minutes = \(Int((minutes?[0])!)), seconds = \(Int((seconds?[0])!))") // year = 225, month = 7, day = 13, hour = 15, minutes = 56, seconds = 56

当我修改let year = characteristic.value?.subdata(in: 0..&lt;2)部分时,转换值应该是2017。但是,仅输出 225 值。我不知道如何解决这部分。

请帮帮我。

【问题讨论】:

  • 您想通过将Date 转换为Data 来达到什么目的?
  • @mag_zbc BLE 目的是设置与BLE设备配对的时间。另外,我很担心如何在Objective c代码中用swift*(int *)[[date subdataWithRange:NSMakeRange(0, 2)] bytes]实现这部分。
  • 为什么你不把你的日期转换成 NSString 然后 NSData 和你的 NSData ----> NSString ----> NSDate。

标签: ios objective-c swift swift3


【解决方案1】:

您将获取年份值作为 UInt8,其范围仅为 0-255,因此请使用 UInt32

var yearVal: UInt32 = 0
(year as! NSData).getBytes(&yearVal, length: MemoryLayout.size(ofValue: year))

【讨论】:

  • 对不起。我不是我想要的答案。
【解决方案2】:

您很幸运,您的 Objective-C 代码可以在读取未分配内存并忽略字节序问题时正常工作。

考虑这条线:

int month = *(int *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes];

在这里,您将一个指向单个字节的指针转换为指向 4 个字节的指针(int 上的大小),然后读取 4 个字节并将它们存储在 month 中。 幸运您读取的额外三个字节恰好为零。

然后是字节序问题,不同的cpu架构在内存中以不同的顺序存储多字节值。 little-endian 架构首先存储最低有效字节,big-endian 存储最高有效字节。

例如4字节整数0xDEADBEEF在小端机器上存储为字节序列EFBEADDEDEADBE、@ 987654332@ 使用大端序。就上面的month 值而言,这意味着如果字节为06,那么当您读取这4 个字节时(并且仅当那些额外的字节为零时),您可能会返回整数0x06000000

对于month 情况,您可以加载字节然后转换为整数:

int month = (int *)(*(Byte *)[[date subdataWithRange:NSMakeRange(2, 1)] bytes]);

将年份转换为两个字节时,您会经历冗长的过程:

NSMutableData *yearData = [[NSMutableData alloc] initWithBytes:&year length:sizeof(year)];
int year1 = *(int *)[[yearData subdataWithRange:NSMakeRange(0, 1)] bytes];
int year2 = *(int *)[[yearData subdataWithRange:NSMakeRange(1, 1)] bytes];

这会将整数转换为 NSData,生成更多 NSData 值,每个值包含 1 个字节,然后为每个值加载 4 个字节 - 与上述问题相同,但在这种情况下,您只会存储 1 bytes 数组中的字节,多余的字节是否垃圾都没关系。

这个过程很复杂,你最好坚持整数运算来获得这两个值。您可以使用除法和余数运算,或按位移位和掩码运算来获取各个字节。

例如先用小数来演示:

int year = 2017;
int firstDigit = year % 10;           // the remainder of year / 10 => 7
int secondDigit = (year / 10) % 10;   // 1
int thirdDigit = (year / 100) % 10;   // 0
int fourthDigit = (year / 1000) % 10; // 2

要提取字节只需更改除数:

int year = 2017;                 // = 0x7E1
int loByte = year % 256;         // = 0xE1
int hiByte = (year / 256) % 256; // = 0x7

最后你可以使用按位移位和屏蔽:

int year = 2017;                 // = 0x7E1
int loByte = year & 0xFF;        // = 0xE1
int hiByte = (year >> 8) & 0xFF; // = 0x7

使用逐位运算使得字节拆分更加明显,但除法和取余达到相同的结果。

就您的 Objective-C 代码而言,这一切意味着什么?那么你的两个方法中的第二个可以写成:

+ (NSDate *) dataToDate:(NSData *)data
{
   NSDateComponents *components = [[NSDateComponents alloc] init];
   const Byte *bytes = data.bytes;
   components.year = (NSInteger)bytes[0] | ((NSInteger)bytes[1] << 8); // reassemble 2-byte value
   components.month = (NSInteger)bytes[2];
   components.day = (NSInteger)bytes[3];
   components.hour = (NSInteger)bytes[4];
   components.minute = (NSInteger)bytes[5];
   components.second = (NSInteger)bytes[6];

   NSCalendar *calendar = [NSCalendar currentCalendar];

   return[calendar dateFromComponents:components];
}

这要简单得多,不读取随机内存,并且更容易转换为 Swift

这里采用相同的方法是您在 Swift 中的第一个方法:

func toData(_ date : Date) -> Data
{
   let cal = Calendar(identifier: .gregorian)
   let comp = cal.dateComponents([.day,.month,.year,.hour,.minute,.second], from: date)
   let year = comp.year!
   let yearLo = UInt8(year & 0xFF) // mask to avoid overflow error on conversion to UInt8
   let yearHi = UInt8(year >> 8)
   let settingArray = [UInt8]([
      yearLo
      , yearHi
      , UInt8(comp.month!)
      , UInt8(comp.day!)
      , UInt8(comp.hour!)
      , UInt8(comp.minute!)
      , UInt8(comp.second!)
      ])
   return Data(bytes: settingArray)
}

最后,你可以像数组一样在 Swift lust 中索引 Data 类型,所以上面的 Objective-C 行:

components.month = (NSInteger)bytes[2];

其中bytes 来自调用NSDatabytes 可以直接用Swift 编写为:

components.month = Int(data[2])

其中dataData 值。

上述方法并不能解决您实际遇到的问题,因为它避免了将数据值拆分为位并尝试从中获取额外值的混乱 - 只需索引字节并使用强制转换进行转换。

您需要的其余代码留作练习!

HTH

【讨论】:

  • 原始代码中的另一个问题仍然存在于您的答案中:MemoryLayout.size(ofValue: settingArray) 不是数组元素的数量。因此,您将获得 8 个字节的数据,而不是 7 个。它应该是 Data(bytes: settingArray, count: settingArray.count) 或只是 Data(bytes: settingArray)
  • @MartinR - 谢谢,我完全错过了。已确认并编辑。
  • @CRD 很抱歉回复晚了。我按照您建议的方式稍作修改解决了这个问题。非常感谢。
猜你喜欢
  • 2021-02-23
  • 2012-06-28
  • 1970-01-01
  • 1970-01-01
  • 2021-03-18
  • 1970-01-01
  • 1970-01-01
  • 2014-01-14
  • 2014-12-04
相关资源
最近更新 更多