2016-01-27 2 views
1

У меня есть следующий код площадка:мутировать Inout функция параметра Я в асинхронном блоке

import UIKit 
import XCPlayground 

class A { 

    var arr : [UIImage] = [] 

    func addItem(inout localArr: [UIImage]) { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
      localArr.append(UIImage()) 
      print("from inside function localArr: \(localArr)") 
      print("form inside function: \(self.arr)") 
     } 
    } 
} 

let a = A() 
a.addItem(&a.arr) 
print("instant print :\(a.arr)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("print after delay: \(a.arr)") 
} 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

Выход есть:

instant print :[] 
from inside function localArr: [<UIImage: 0x7f99e8706f10>, {0, 0}] 
form inside function: [] 
print after delay: [] 

Мой вопрос, почему localArr не то же самое, как self.arr внутри addItem и не то же самое, что a.arr снаружи? Мое предположение состояло в том, что когда я передаю параметр как inout, я должен иметь возможность работать с фактическим объектом, а не с копией, но, очевидно, это не то, что происходит.

Редактировать: Так спасибо dfri Ответ Я знаю, почему это не работает. inout действительно call-by-copy-restore, проверьте другой ответ here. Итак, какое-либо предложение о том, как сделать закрытие для привязки к исходному объекту? Или, может быть, я должен использовать другую технику для достижения того, чего хочу?

+0

ваш код и выход не match..please редактировать их –

+0

Edited, один оператор печати отсутствовал внутри 'addItem' функция. – lawicko

ответ

2

Для некоторой теории на inout ключевое слово, см следующий ответ:

Не зависит от поведенческих различий между копией в копирования из и вызова по ссылке.

...

Когда функция возвращает ваши изменения в оригинале являются переписывается со значением копии. Не следует зависеть от реализации оптимизации обратного вызова, чтобы попытаться сохранить изменения .

Теперь ваша addItem функция завершит свой призыв немедленно и, следовательно, выполнить копирование в/задачи копирования-за inout до отсроченной отправки в функции. Это делает изначально неприемлемым использование отложенных отправлений в пределах с параметрами inout, по крайней мере, если задержка является той, которая пытается изменить параметр inout.

Чтобы увидеть это, проследите ссылки (а не отслеживайте значения) какого-либо массива и как они могут показать мутацию массива во время выполнения нашего примера.

func foo(inout bar: [Int]) { 
    var pBar : UnsafePointer<Int> = UnsafePointer(bar) 
    print("2: \(pBar)") 
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
     pBar = UnsafePointer(bar) 
     print("3: \(pBar)") 
     bar[0] = 2 
     pBar = UnsafePointer(bar) 
     print("4: \(pBar)") 
    } 
} 

var a : [Int] = [1] 
var pA : UnsafePointer<Int> = UnsafePointer(a) 
print("1: \(pA)") 
foo(&a) 
print("foo call to a finished, a = \(a)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(5 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("value of a naturally not changed here = \(a)") 
    pA = UnsafePointer(a) 
    print("5: \(pA)") 
} 

XCPlaygroundPage.currentPage.needsIndefiniteExecution = true 

Выход самопонятны:

1: 0x00007fe19271e930 
2: 0x00007fe19271e930 
foo call to a finished, a = [1] <-- call to foo finished, 'inout' procedure complete 
3: 0x00007fe19271e930   <-- dispatch in `foo` starts 
4: 0x00007fe1927085e0   <-- mutates 'bar': 'bar' copied (and never 
            "returned" as this step is already finished) 
value of a naturally not changed here = [1] 
5: 0x00007fe19271e930   <-- naturally 'a' wont see the effect of the 
            delayed mutation in foo 
+0

Спасибо за объяснение, это действительно помогает понять 'inout'. Есть ли у вас какие-либо предложения о том, как реально мутировать массив (или любой другой переданный объект) внутри блока с задержкой? – lawicko

+0

@ lawicko Счастливые помочь. Я должен уйти на несколько часов, но я могу посмотреть на него, когда вернусь, учитывая, что к тому времени никто не помог вам. – dfri

+0

@lawicko использовать ссылочный тип. Я считаю, NSArray будет делать –

1

Swift Массивы типов значений. Который всегда копирует при назначении. Используйте NSMutableArray, если вы хотите ссылаться на исходный массив. Тогда нет также никакой необходимости inout

class A { 

    var arr : NSMutableArray = [] 

    func addItem(localArr: NSMutableArray) { 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(2 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
      localArr.addObject(UIImage()) 
      print("from inside function localArr: \(localArr)") 
      print("form inside function: \(self.arr)") 
     } 
    } 
} 

let a = A() 
a.addItem(a.arr) 
print("instant print :\(a.arr)") 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (Int64)(3 * NSEC_PER_SEC)), dispatch_get_main_queue()) {() -> Void in 
    print("print after delay: \(a.arr)") 
} 

печати:

instant print :(
) 
from inside function localArr: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
form inside function: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
print after delay: (
    "<UIImage: 0x7ffe1872b5f0>, {0, 0}" 
) 
+0

Спасибо, я одобрил ваш комментарий, поскольку NSMutableArray действительно работает в этом случае. Однако ответ dfri на самом деле объяснил оригинальный вопрос, поэтому исходный код не работал. – lawicko

+0

@ lawicko Я знаю;) Я просто пытался помочь вам, пока dfri был на работе. –

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