2017-05-06 4 views
5

Hier ist eine einfache Swift FunktionSchnelle Konstanten (mit einer Berechnung) in Funktionen?

fileprivate func test()->String{ 
    let c = Array("abc".characters) 
    let k = UInt32(c.count) 
    let r = Int(arc4random_uniform(k)) 
    return String(c[r]) 
} 

(ich dieses Beispiel gewählt, weil, natürlich, es ist etwas Sie Milliarden mal nennen können irgendeine Art von Ausgabe zu erzeugen, so dass Sie möglicherweise bei der Einrichtung der zwei für die Leistung betroffen sein Konstanten.)

Beachten Sie, dass es ein bisschen Berechnung zu c zu tun, und in der Tat zu kc zu verwenden ist.

Meine Frage ist einfach: Jedes Mal, wenn Sie

diese Funktion aufrufen
test() 
test() 
test() 

in der Tat ist es k nicht berechnen und/oder cjedes Mal wenn ich es nennen, oder in der Tat sind sie nur einmal berechnet ?

(wenn "nur einmal", dann als Kuriosität: tut es das erste Mal ich die Funktion aufrufen? Oder vielleicht der Compiler arrangiert, um es beim Start separat getan zu haben? Oder für diese Angelegenheit weiß es es kann berechnen sie während der Kompilierung?)


ich oft global berechneten Eigenschaften verwenden, eher wie dieses

let basicDF : DateFormatter = { 
    print("this will only be done once per launch of the app") 
    let formatter = DateFormatter() 
    formatter.dateFormat = "yyyy-MM-dd" 
    return formatter 
}() 

(vielleicht mit fileprivate) Wenn die Antwort auf die obige Frage „nein, c und‚k 'werden jedes Mal berechnet, wenn Sie c all test ", wie kann man dann eine Art statisch berechnete Eigenschaft in eine Funktion einfügen ??

Antwort

3

Nein, in Ihrem speziellen Fall, der Compiler zur Zeit nicht optimiert c und/oder k zu konstanten Ausdrücken, das nur einmal ausgewertet werden (dies wird durch examining the IR in einem optimierten Build zu sehen) - obwohl dies alles unterworfen ist Ändern Sie mit zukünftigen Versionen der Sprache.

aber es ist erwähnenswert, dass es zur Zeit dies für einfacheren Ausdrücke tun kann, zum Beispiel:

func foo() -> Int { 
    return 2 + 4 
} 

Der Compiler den Zusatz zur Compile-Zeit auswerten kann, so dass die Funktion nur nicht return 6 (und dann kann das sein inline). Aber natürlich sollten Sie sich solche Optimierungen erst einmal Sorgen machen, wenn Sie die gegebene Funktion tatsächlich als Performance-Engpass identifiziert haben.

Eine nette Trick statische Konstanten in einer Funktion zu erhalten, ist ein Fall lose enum mit statischen Eigenschaften in der Funktion Bereich zu definieren, in denen Sie Ihre konstante Ausdrücke definieren können: sowohl Jetzt

func test() -> String { 

    enum Constants { 
     static let c = Array("abc".characters) 
     static let k = UInt32(c.count) 
    } 

    let r = Int(arc4random_uniform(Constants.k)) 
    return String(Constants.c[r]) 
} 

die initialiser Ausdrücke für c und k werden nur einmal ausgewertet, und dies erfolgt bei der ersten Verwendung (dh wenn die Funktion zum ersten Mal aufgerufen wird).

Und natürlich, wie Sie zeigen, können Sie einen sofort-evalutated Verschluss, um einen mehrzeilige Initialisierung Ausdruck zu haben, verwenden:

enum Constants { 
    static let c: [Character] = { 
     // ... 
     return Array("abc".characters) 
    }() 
    // ... 
} 
+0

Fantastisch, so ist es in Swift enumstatisch, Statik zu machen. Hervorragend, danke. Entscheidende Infos aus dem Bitcode, danke. – Fattie

1

Ich denke, Sie sollten annehmen, dass c und k jedes Mal berechnet werden. Die Berechnung könnte als Implementierungsdetail des Compilers weg optimiert werden, aber ich würde nicht darauf zählen, wenn ich Sie wäre.

Swift hat keine Entsprechung zu einer C static lokalen Variablen (dh eine "automatische" Variable innerhalb einer Funktion, deren Wert zwischen Aufrufen der Funktion beibehalten wird).

Wenn Sie wirklich sicherstellen möchten, dass k nur einmal berechnet wird, erstellen Sie eine echte Konstante (d. H. Auf Klassenebene). Natürlich müssen Sie dann auch das gleiche für c tun, wie Sie es in Ihren späteren Berechnungen benötigen. Es scheint wie ein dummes Beispiel in diesem Fall, aber ich tue dies oft, wenn die Sache Schwergewicht geschaffen wird, ist, wie ein Bild oder Ansicht, die verwendet wird immer und immer wieder:

class MyView : UIView { 
    lazy var arrow : UIImage = self.arrowImage() 
    func arrowImage() -> UIImage { 
     // ... big image-generating code goes here ... 
    } 
} 

Ich war arrowImage() über Berufung und über bis ich mir gesagt habe, warte, ich kann das eine Konstante machen (hier ausgedrückt als lazy var) und es nur einmal berechnen, nämlich das erste Mal auf arrow zugegriffen wird.

+0

Ich sehe, so „faul var“ ist die Lösung bei der Klassenstufe ('lazy var c = Array (" abc ".characters)', so einfach); kann in einer Funktion nicht tun. Tolle Info Danke. – Fattie

Verwandte Themen