我正在努力将 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
存储为字节序列 EF
、BE
、AD
、DE
在小端机器上和 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
来自调用 NSData
的 bytes
可以直接用 Swift 写成:
components.month = Int(data[2])
其中 data
是 Data
值。
上述方法并没有回答您实际遇到的问题,因为它避免了将数据值拆分为位并尝试从中提取额外值的困惑 - 只需索引字节并使用强制转换进行转换。
您需要的其余代码留作练习!
HTH
关于ios - swift3 日期到数据,数据到日期转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45077198/