2015-07-18 8 views
11

Ho guardato a domande simili ma non ho visto una risposta di cui sono soddisfatto.Passaggio rapido struttura per riferimento?

È possibile o consigliabile passare le strutture per riferimento? Se é cosi, come?

Ecco un codice come riferimento per gli esempi:

struct MyData { 
    var contentId: Int = 0 
    var authorId: Int = 0 
    var image: UIImage = UIImage(named: "myimage") 
} 

Come vedete la mia ragione principale per farlo è perché non avere la mia immagine moltiplicando in tutto il luogo.

+1

Per fortuna l'immagine è un tipo di riferimento e si dovrà sostenere lo stesso costo copiando la struttura in base al valore come si farebbe passando il riferimento a UIImage. –

+0

questa sarebbe una buona risposta con una fonte – Esqarrouth

risposta

31

Gli schemi possono essere passati per riferimento utilizzando la parola chiave inout e l'operatore &.

struct Test { 
    var val1:Int 
    let val2:String 

    init(v1: Int, v2: String) { 
     val1 = v1 
     val2 = v2 
    } 
} 

var myTest = Test(v1: 42, v2: "fred") 

func change(test: inout Test) { 
    // you can mutate "var" members of the struct 
    test.val1 = 24 

    // or replace the struct entirely 
    test = Test(v1: 10, v2: "joe") 
} 
change(test: &myTest) 
myTest // shows val1=10, val2=joe in the playground 

Questa pratica è sconsigliato a meno che non si può dimostrare che è l'unico modo per ottenere le prestazioni necessarie in una situazione critica.

Si noti che non si risparmia l'onere di copiare UIImage in questo modo. Quando si inserisce un tipo di riferimento come membro di una struct, si copia ancora il riferimento solo quando lo si passa per valore. Non stai copiando il contenuto dell'immagine.

Un'altra cosa importante da sapere sulle prestazioni della struttura è copy-on-write. Molti tipi built-in come Array sono tipi di valore, eppure sono molto performanti. Quando passi attorno a una struttura in Swift, non ti accollerai l'onere di copiarlo finché non lo cambierai.

Per ulteriori informazioni, consulta lo WWDC video on value types.

3

Prima di tutto, se si passa una struttura viene normalmente passata per valore. Anche se tutte le proprietà del struct vengono copiati solo il puntatore di proprietà che sono tipi di riferimento simili UIImage ottiene duplicati (solo 8 byte):

var data1 = MyData() 
var data2 = data1 
// both data1 and data2 point to the same image 

Anche il compilatore di ottimizzare il codice in modo struct ottenere internamente passati per riferimento e copiati se necessario.

Come esempio di passare una struttura per riferimento nel codice di livello superiore è possibile utilizzare inout parametri: Quindi un parametro inout può essere passato per riferimento, ma genericamente di Swift di attuare inout è che il parametro si passa per valore e dopo la funzione restituisce viene riassegnata.

Sebbene il compilatore ottimizzi la chiamata di funzione in modo da poter ottenere un riferimento reale in alcune situazioni. Questa ottimizzazione riguarda solo le variabili che non sono calcolate o hanno un osservatore delle proprietà come willSet e didSet (e probabilmente altri casi).

Così si dovrebbe fare affidamento solo sulla istanza corrente che non è nel campo di applicazione della funzione:

struct Test { 
    var value = 0 
} 

// case 1 
var myTest = Test() 

// case 2 
var myTest = Test() { 
didSet { print("I was set") } 
} 

// case 3 
var myTest: Test { 
get{ return Test() } 
set{ print("I set myself") } 
} 

func mutateTest(inout t: Test) { 
    // directly referencing to myTest 

    myTest.value // value = 0 in all cases 

    t.value = 42 
    myTest.value // value = 42 in case 1 ; value = 0 in case 2 and 3 

    t = Test() // nothing gets printed 
    myTest.value // value = 0 in all cases 

    t = Test() // nothing gets printed 
    t.value = 3 // value = 3 in case 1 ; value = 0 in case 2 and 3 
} 

changeTest(&myTest) 
//case 2: "I was set", case 3 "I set myself" get printed now 

myTest.value // value = 3 in all cases 

Come si può vedere myTest e t sono equivalenti solo in caso 1 ("veri" semantica di riferimento) . Quindi questo fa una grande differenza se si fa riferimento anche a myTest nella funzione stessa. Ma finché non lo fai, sei a posto.