2016-06-27 4 views
2

Ich habe wirklich mit der Tatsache zu kämpfen, dass someData[start...stop] eine MutableRandomAccessSlice zurückgibt. Meine someData war eine let von Anfang an, also warum sollte ich eine Veränderliche Sache wollen? Warum bekomme ich nicht einfach eine RandomAccessSlice. Was wirklich frustrierend ist, ist, dass es ein Ding zurückgibt, das ziemlich API-inkompatibel mit der ursprünglichen Quelle ist. Mit einer Data kann ich .withUnsafeBytes verwenden, aber nicht so mit diesem Nachwuchs. Und wie Sie das Slice wieder in Daten umwandeln, ist auch nicht klar. Es gibt keine Init, die einen davon braucht.Daten <-> MutableRandomAccessSlice

Ich könnte die.Methode anstelle von Subscripting verwenden, aber dann, was ist der Punkt des Index, wenn ich immer nur eine Untersammlungsdarstellung wollen, die sich wie die ursprüngliche Sammlung verhält. Darüber hinaus kann die Methode subdata nur offene Teilbereiche ausführen, weshalb der Index sowohl geschlossene als auch offene Operationen ausführen kann. Ist das nur etwas, was sie noch nicht für das Swift3-Finale erreicht haben?

Antwort

4

Denken Sie daran, dass die MutableRandomAccessSlice Sie zurück erhalten, ist ein Wert Typ, kein Referenztyp. Es bedeutet nur, können Sie es ändern, wenn Sie mögen, aber es hat nichts mit der Sache zu tun, in Scheiben geschnitten Sie es aus:

let x = Data(bytes: [1,2,3]) // <010203> 
var y = x[0...1] 
y[0] = 2 
x // <010203> 

Wenn Sie in der code suchen, Sie werden bemerken, dass die Absicht ist, zurückzukehren ein benutzerdefinierte Slice-Typ:

public subscript(bounds: Range<Index>) -> MutableRandomAccessSlice<Data> { 
    get { 
     return MutableRandomAccessSlice(base: self, bounds: bounds) 
    } 
    set { 
     // Ideally this would be: 
     // replaceBytes(in: bounds, with: newValue._base) 
     // but we do not have access to _base due to 'internal' protection 
     // TODO: Use a custom Slice type so we have access to the underlying data 
     let arrayOfBytes = newValue.map { $0 } 
     arrayOfBytes.withUnsafeBufferPointer { 
      let otherData = Data(buffer: $0) 
      replaceBytes(in: bounds, with: otherData) 
     } 
    } 
} 

das hieß, wird eine benutzerdefinierte Scheibe noch auf eine Funktion nicht akzeptabel sein, die ein Datum erfolgt. Das ist jedoch konsistent mit anderen Typen, wie Array, das in eine ArraySlice schneidet, die nicht dort übergeben werden kann, wo ein Array erwartet wird. Dies ist beabsichtigt (und wahrscheinlich auch für Data aus den gleichen Gründen). Die Sorge ist, dass ein Slice den gesamten Speicher, der ihn unterstützt, "anheftet". Wenn Sie also ein 3-Byte-Segment aus einem Megabyte-Datenelement herausgenommen und in einem Ivar gespeichert haben, muss das gesamte Megabyte hängen bleiben. Die Theorie (nach Swift Devs mit denen ich sprach) ist, dass Arrays massiv sein könnte, so dass Sie mit dem Schneiden sie vorsichtig sein müssen, während Strings sind in der Regel viel kleiner, so ist es ok für einen String in einen String zu schneiden.

Nach meiner Erfahrung so weit, Sie wollen in der Regel subdata(in:). Ich experimentiere damit, dass es in der Geschwindigkeit dem Slicing sehr ähnlich ist, also glaube ich, dass es immer noch Kopie beim Schreiben ist (aber es scheint die Erinnerung in meinen anfänglichen Tests nicht zu fixieren). Ich habe es bisher nur auf dem Mac getestet. Es ist möglich, dass auf iOS-Geräten größere Leistungsunterschiede bestehen.

+0

Diese sehr klare und prägnante Antwort ist! –

0

Basierend auf Robs Kommentare, habe ich nur noch die folgende Pythonesque Index Erweiterung:

extension Data { 
    subscript(start:Int?, stop:Int?) -> Data { 
     var front = 0 
     if let start = start { 
      front = start < 0 ? Swift.max(self.count + start, 0) : Swift.min(start, self.count) 
     } 
     var back = self.count 
     if let stop = stop { 
      back = stop < 0 ? Swift.max(self.count + stop, 0) : Swift.min(stop, self.count) 
     } 
     if front >= back { 
      return Data() 
     } 
     let range = Range(front..<back) 
     return self.subdata(in: range) 
    } 
} 

So kann ich nur

tun können
let input = Data(bytes: [0x60, 0x0D, 0xF0, 0x0D]) 
input[nil, nil] // <600df00d> 
input[1, 3]  // <0df0> 
input[-2, nil] // <f00d> 
input[nil, -2] // <600d> 
Verwandte Themen