簡體   English   中英

Swift字符串內插性能

[英]Swift string interpolation performance

在我的iOS / Swift項目中,我有很多print()語句。 我編寫了如下的全局重寫,以便在發行版本中將其忽略:

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
        Swift.print(items, separator: separator, terminator: terminator)
    #endif
}

調用print() ,有時會傳入帶有昂貴的自定義debugDescription屬性的對象,例如:

print("Value of myArray: \(myArray)")

使用myArray實現自定義debugDescription如下所示:

var debugDescription: String {
    get {
        // Serialise the array for printing
    }
}

我的問題是,在將字符串傳遞給print()或之后會計算debugDescription值嗎? #if DEBUG預處理程序指令會從發行版本中消除計算嗎?

編輯:我知道debugDescription是一個計算的屬性,我不確定何時調用它。 我不是我自己稱呼它。 它會在字符串插值過程中自動調用。 因此,如果Swift在將字符串傳遞給print()之前對其進行插值,它仍會計算該屬性。 但是,如果Swift而是保存“指令”,並且僅在內部內置的Swift.print()函數中評估字符串,那么我可以獲得性能提升。 因此,這個問題實際上是關於Swift如何處理有關性能的字符串插值。

#if DEBUG預處理程序指令是否會從發行版本中消除計算?

不,不會。 Swift會在調用函數時評估所有函數參數。 您可以在調試器中或通過在您的debugDescription實現中添加對Swift.print的調用來驗證這一點。 例如,創建具有以下內容的文件:

// test.swift
struct A: CustomDebugStringConvertible {
    let value: Int

    var debugDescription: String {
        Swift.print("Calling debugDescription")
        return "A: \(value)"
    }
}

func print(_ items: Any..., separator: String = " ", terminator: String = "\n") {
    #if DEBUG
        Swift.print(items, separator: separator, terminator: terminator)
    #endif
}

let a = A(value: 42)
print("Value of a: \(a)")

然后,在終端中:

> swift test.swift
Calling debugDescription

如您所見,即使您的print功能沒有執行任何操作,也將print "Calling debugDescription" (即,對debugDescription進行評估)。 現在讓我們設置DEBUG標志:

> swift -D DEBUG test.swift
Calling debugDescription
["Value of a: A: 42"]

這就是為什么Swift標准庫中的類似函數(例如assert )將自動閉合用於其一個或多個參數的原因。 @autoclosure屬性將函數參數包裝在閉包中。 這樣,被調用的函數可以決定是否以及何時對表達式求值(通過調用函數)。 這對於呼叫者是完全透明的。

不幸的是, @autoclosure不適用於可變參數(如Any... ),所以我認為沒有一種方法可以在Swift 4.0中精確地再現您想要的內容。 但是,如果您可以使用帶有單個Any參數的print函數,則可以這樣定義函數:

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
        Swift.print(item(), separator: separator, terminator: terminator)
    #endif
}

現在,該函數將不會計算其第一個參數,除非您調用item() ,這僅發生在#if DEBUG塊內部,因此發行版本中沒有任何開銷。

預處理不會將#if DEBUG內部的代碼包含到發布代碼中。 因此,由於它是計算屬性,所以不用擔心,對發行代碼優化沒有影響

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM