2017-07-13 4 views
2

Ich arbeite an der Änderung des Codes erstellt in Ziel c zu swift3.
Ich möchte den folgenden Code in den mit Ziel c erstellten Code swift3 ändern.swift3 Datum zu Daten, Daten zu Datum konvertieren

Objective c NSDate zu NSData Code:

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 zu NSDate Code:

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 Date Datencode:

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 Daten zu Datumscode :

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 

Wenn ich den let year = characteristic.value?.subdata(in: 0..<2) Teil modifiziere, sollte der Umwandlungswert 2017 sein. Es werden jedoch nur 225 Werte ausgegeben. Ich weiß nicht, wie ich diesen Teil lösen soll.

Bitte helfen Sie mir.

+0

Was möchten Sie erreichen, indem Sie "Date" in "Data" konvertieren? –

+0

@mag_zbc BLE Der Zweck ist, die Zeit einzustellen, wenn ein Pairing mit einem BLE-Gerät durchgeführt wird. Darüber hinaus mache ich mir Sorgen darüber, wie dieser Teil in swift '* (int *) [[date subdataWithRange: NSMakeRange (0, 2)] Bytes] in Objective c-Code implementiert werden kann. – bongpro

+0

Warum konvertieren Sie Ihr Datum nicht in NSString und dann NSData, und Ihre NSData ----> NSString ----> NSDate. –

Antwort

1

Sie sind sehr glücklich, Ihr Objective-C-Code funktioniert, wie Sie nicht zugewiesene Speicher lesen und Endian Probleme zu ignorieren.

Betrachten Sie die Zeile:

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

Hier können Sie einen Zeiger auf ein Byte einnehmen, es auf einen Zeiger auf 4 Bytes (die Größe auf einem int) Gießen, und dann 4 Bytes zu lesen und zu speichern in month. Durch Glück sind die zusätzlichen drei Bytes, die Sie lesen, zufällig Null.

Dann gibt es das Endian-Problem, verschiedene CPU-Architekturen speichern Multi-Byte-Werte in verschiedenen Ordnungen im Speicher. Eine Little-Endian-Architektur speichert zuerst das niedrigstwertige Byte, ein Big-Endian-Byte das signifikanteste Byte.

z. Die 4-Byte-Ganzzahl 0xDEADBEEF als Bytefolge EF, BE, AD, DE auf einer Little-Endian-Maschine und als DE, AD, BE, EF auf einem Big-Endian einem gespeichert. Was das in Bezug auf Ihren month Wert oben bedeutet, wenn das Byte 06 ist, dann könnten Sie die Ganzzahl 0x06000000 zurückbekommen, wenn Sie diese 4 Bytes lesen (und nur, wenn diese zusätzlichen Bytes Nullen sind).

Für den month Fall, dass Sie die Byte laden konnte und dann in eine ganze Zahl konvertieren:

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

Wenn das Jahr zu zwei Bytes konvertieren Sie die langatmigen Prozess durchlaufen:

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]; 

Diese wandelt eine ganze Zahl in eine NSData, macht mehr NSData Werte mit jeweils 1 Byte, und lädt dann 4 Bytes für jeden - das gleiche Problem wie oben, aber in diesem Fall, wie Sie nur 1 Byte in Ihremspeichern werdenArray ist es egal, ob die zusätzlichen Bytes Müll sind.

Der Prozess ist verschachtelt, Sie würden besser mit Integer-Operationen bleiben, um die beiden Werte zu erhalten. Sie können die einzelnen Bytes mit Divisions- und Restoperationen oder bitweisen Shift- und Maskierungsoperationen erhalten.

z. zuerst unter Verwendung von dezimal zu demonstrieren:

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 

die Bytes zu extrahieren nur den Divisor ändern:

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

Schließlich können Sie bitweise Verschiebung und Maskierung verwenden:

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

Mit bit- weise Operationen macht die Byte-Aufspaltung deutlicher, aber Dividieren und Rest erreichen das gleiche Ergebnis.

Was bedeutet das alles in Bezug auf Ihren Objective-C-Code? Nun, die zweite Ihrer beiden Methoden kann geschrieben werden:

+ (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]; 
} 

Dieses viel weniger komplex ist, liest nicht zufällig Speicher, und ist einfacher zu Swift zu konvertieren.

den gleichen Ansatz hier Es folgt die erste Methode in 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) 
} 

Sie Schließlich kann, Index der Data Typ in Swift Lust wie ein Array, so dass die obige Objective-C-Linie:

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

wo bytes kam Aufruf NSData ‚s bytes kann direkt in Swift geschrieben werden:

components.month = Int(data[2]) 

wobei data der Wert Data ist.

Der obige Ansatz beantwortet nicht das Problem, das Sie tatsächlich hatten, weil es das Durcheinander mit Datenwerten in Bits zerlegt und versucht, zusätzliche Werte von ihnen zu versuchen - indexieren Sie einfach das Byte und konvertieren Sie mit einem Cast.

Der Rest des Codes, den Sie benötigen, bleibt als Übung übrig!

HTH

+0

Es gibt ein weiteres Problem im ursprünglichen Code, das immer noch in Ihrer Antwort vorhanden ist: 'MemoryLayout.size (ofValue: settingArray)' ist * nicht * die Anzahl der Array-Elemente. Daher erhalten Sie 8 Byte Daten anstelle von 7. Es sollte 'Data (Bytes: settingArray, count: settingArray.count)' oder einfach 'Data (bytes: settingArray)' sein. –

+1

@MartinR - Danke, das hätte ich komplett vermisst. Bestätigt und bearbeitet – CRD

+0

@CRD Es tut mir leid, zu spät zu antworten. Ich löste das Problem mit einer leichten Änderung in der Art, wie Sie es vorgeschlagen haben. Vielen Dank. – bongpro

0

Sie Jahreswert als UInt8 sind das Abrufen der nur Bereich von 0-255 haben so UInt32 verwenden

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

Entschuldigung. Ich bin nicht die Antwort, die ich will. – bongpro