2016-08-06 31 views
1

Ich habe ein Objekt, das Pixel Zeile für Zeile (genau wie alte Fernseher) ausgegeben wurde. Dieses Objekt schreibt einfach Bytes in ein zweidimensionales Array. So gibt es eine Anzahl von horizontalen Linien mit jeweils einer Anzahl von Pixeln. Diese Zahlen sind fest: Es gibt x Anzahl der horizontalen Linien und jede Linie y Anzahl der Pixel. Ein Pixel ist eine Struktur aus Rot, Grün und Blau.Erfordern ein Array, um eine Mindestgröße in Swift-Protokoll zu sein

Ich möchte, dass Clients dieser Klasse ihr eigenes Objekt anschließen, auf das diese Werte geschrieben werden können, da ich möchte, dass dieser Code zwei gut auf Apple-Plattformen funktioniert (wo CALayer vorhanden ist), aber auch auf anderen Plattformen (zB Linux, wo das Rendering ohne CALayer durchgeführt werden muss). So dachte ich an Protokollen wie diese machen:

struct Pixel 
{ 
    var red: UInt8 = 0 
    var green: UInt8 = 0 
    var blue: UInt8 = 0 
} 
protocol PixelLine 
{ 
    var pixels: [Pixel] { get } 
} 
protocol OutputReceivable 
{ 
    var pixelLines: [PixelLine] { get } 
} 

Diese Protokolle woul

let pixelLineIndex = ... // max 719 
let pixelIndex = ... // max 1279 

// outputReceivable is an object that conforms to the OutputReceivable protocol 
outputReceivale.pixelLines[pixelLineIndex][pixelIndex].red = 12 
outputReceivale.pixelLines[pixelLineIndex][pixelIndex].green = 128 
outputReceivale.pixelLines[pixelLineIndex][pixelIndex].blue = 66 

stellen sich zwei Fragen wie

irgendwann verwendet werden:

  • wie das Protokoll Pixelline verlangen um ein Minimum von 1280 Pixel-Einheiten im Array zu haben und das Protokoll OutputReceive mindestens 720 PixelLine-Elemente im Array?

  • Wie ich von a video gelernt habe, kann die Verwendung von Generika dem Compiler helfen, optimalen Code zu erzeugen. Gibt es eine Möglichkeit für mich, Generika zu verwenden, um leistungsfähigeren Code zu erzeugen, und dann einfache Protokolle als Typ zu verwenden?

Antwort

0

Es gibt keine abhängigen Typen in Swift. Sie können nicht direkt verlangen, dass Arrays eine Mindestgröße haben. Sie können neue Typen erstellen, die nur mit bestimmten Daten erstellt werden können. In diesem Fall wäre das bessere Modell also PixelLine eine Struktur anstelle eines Protokolls. Dann können Sie eine init? haben, die sicherstellt, dass es legal ist, bevor Sie es verwenden.

Ein einfacher Struct Wrapper um ein Array ist kostenlos im Speicher und äußerst kostengünstig im Versand. Wenn Sie mit einem Hochleistungssystem arbeiten, ist eine Struktur, die ein Array umschließt, ein ausgezeichneter Ausgangspunkt.

struct PixelLine { 
    let pixels: [Pixel] 
    init?(pixels: [Pixel]) { 
     guard pixels.count >= 1280 else { return nil } 
     self.pixels = pixels 
    } 
} 

können Sie entweder aussetzen pixels direkt wie dies der Fall ist, oder Sie können PixelLine eine Collection (oder auch nur eine Sequence) machen, die ihre erforderlichen Methoden zu pixels weiterleitet.

+0

Diese Option war mir eingefallen, aber auf diese Weise konnten Clients keine eigene Instanz in mein Pixel-Output-Objekt einklinken. Unter Verwendung Ihres Vorschlags wäre das Pixel, das ausgegeben wird, derjenige, der die Ausgabe-Instanz verkauft, wodurch es weniger effizient ist, Konvertierungen auf der Client-Seite durchzuführen (z. B. invertierter Koordinatenraum, unterschiedlicher Farbraum, Skalierung, Transformation usw.). Ich möchte, dass die Clients dieser Klasse dieses Konvertierungsrecht zulassen, wenn ein Wert festgelegt wird. – Joride

+0

Übrigens, irgendwelche Gedanken darüber, wann Sie 'guard pixels.count> = 1280 ...' versus 'precondition (pixels.count == 1280) ...' verwenden würden? – Joride

+0

Die Art und Weise, wie Sie es sich vorstellen, ist in Swift nicht möglich (oder in jeder gängigen Sprache, die ich kenne; sie wird als abhängige Typen bezeichnet und ist im Allgemeinen ein Forschungsthema im Sprachdesign). Das beste Werkzeug ist, Zeilen in einen konkreten Typ (struct) und nicht in ein Protokoll zu schreiben. Es kann eine Sammlung anstelle eines Arrays akzeptieren, um dem Anrufer mehr Flexibilität zu geben. Eine Init? ist im Allgemeinen besser als eine Vorbedingung, wenn Sie aus einer Datei/einem Netzwerk lesen. Eine Vorbedingung ist besser, wenn der Aufrufer Daten im Code generiert haben soll. Abhängig vom Anwendungsfall. Kann aber zur Übersetzungszeit in Swift nicht gelöst werden. –