2015-07-18 4 views
11

Я смотрел на подобные вопросы, но я не видел ответа, которым я доволен.Swift pass struct по ссылке?

Возможно ли передать структуры по ссылке? Если да, то как?

Вот код в качестве ссылки на примеры:

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

Как вы видите, моя основная причина делать это потому, что не имея мое изображение умножения повсюду.

+1

К счастью, ваше изображение является ссылочным типом, и вы понесете примерно такую ​​же стоимость от копирования структуры по стоимости, как и вы, пройдя ссылку на UIImage. –

+0

это был бы хороший ответ с источником – Esqarrouth

ответ

31

Структуры могут передаваться по ссылке с использованием ключевого слова inout и оператора &.

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 

Эта практика не рекомендуется, если вы не можете доказать, что это единственный способ получить необходимую производительность в критической ситуации.

Обратите внимание, что вы не сэкономите бремя копирования UIImage, выполнив это. Когда вы ставите ссылочный тип как член структуры, вы по-прежнему копируете ссылку только при ее передаче по значению. Вы не копируете содержимое изображения.

Еще одна важная вещь, которая должна знать о производительности структуры: copy-on-write. Многие встроенные типы, такие как Array, являются типами значений, и все же они очень эффективны. Когда вы проходите вокруг структуры в Swift, вы не подвергаетесь бремени копирования, пока не будете мутировать его.

Отъезд WWDC video on value types, чтобы узнать больше.

3

Прежде всего, если вы передаете структуру, она обычно передается по значению. Даже если все свойства структуры копируются только указатель на свойства, которые являются ссылочными типами, как UIImage получает дублируется (всего 8 байт):

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

Также компилятор оптимизирует код таким образом Структуры получить внутренне передаются по ссылке и скопировать если нужно.

В качестве примера пропускания-структуры по ссылке в верхнем уровне коде можно использовать inout параметров: так что inout параметр может быть передан по ссылке, но общий путь Свифта реализации inout является то, что параметр получает пассы по значению и после функция возвращает его переназначение.

Хотя компилятор оптимизирует вызов функции, чтобы вы могли получить истинную ссылку в некоторых ситуациях. Эта оптимизация влияет только на переменные, которые не вычисляются или имеют наблюдателя свойств, такие как willSet и didSet (и, возможно, в других случаях).

Таким образом, вы должны полагаться только на текущем экземпляре, который не находится в области видимости функции:

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 

Как вы можете видеть myTest и t эквивалентны только в случае, если 1 («истинная» эталонная семантика) , Так что это имеет огромное значение, если вы также ссылаетесь на myTest в самой функции. Но пока вы этого не делаете, вам хорошо идти.

Смежные вопросы