ios - swift3 日期到数据,数据到日期转换

标签 ios objective-c swift swift3

我正在努力将 objective-c 中创建的代码更改为 swift3。
我想将下面的代码更改为使用 objective-c 创建的 swift3 代码。

objective-c NSDate 到 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..<2)部分,转换值应该是2017 .然而,只有225值被输出。我不知道如何解决这部分。

请帮帮我。

最佳答案

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

考虑这一行:

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

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

然后是字节序问题,不同的cpu架构在内存中以不同的顺序存储多字节值。小端架构首先存储最低有效字节,大端架构存储最重要的字节。

例如4 字节整数 0xDEADBEEF 存储为字节序列 EFBEADDE 在小端机器上和 DE, AD, BE, EF 在大端机器上-endian 一个。就上面的 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 个字节 - 与上面的问题相同,但是在这种情况下,因为您只会在 bytes 数组中存储 1 个字节,所以额外的字节是否是垃圾并不重要。

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

例如先用小数来演示:

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

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

这一切对您的 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 中像数组一样索引 Data 类型,所以上面的 Objective-C 行:

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

bytes 来自调用 NSDatabytes 可以直接用 Swift 写成:

components.month = Int(data[2])

其中 dataData 值。

上述方法并没有回答您实际遇到的问题,因为它避免了将数据值拆分为位并尝试从中提取额外值的困惑 - 只需索引字节并使用强制转换进行转换。

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

HTH

关于ios - swift3 日期到数据,数据到日期转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45077198/

相关文章:

iOS - UIScrollView 中的 UITableView - 滑动以显示其他内容

ios - 识别点击 iOS 网页内的链接

swift - 为什么在 UIViewPropertyAnimator 中使用 'unowned'

ios - 在 Swift 中对字符串数组进行排序

ios - 将数据传递给另一个带有 NavigationController 的 ViewController

iOS NSCoding NSMutableArray

ios - 异步 Asihttprequest

iphone - 如何使 pdf 页面适合 vfr reader 中的屏幕尺寸

ios - Swift:使用闭包的枚举?

ios - UIViewControllerTransitioningDelegate 在 UITableViewController 顶部显示弹出屏幕