Должна ли асинхронная функция swift сохранять сильную ссылку на объект?

Мы реализовали и расширили NSData, который асинхронно сохраняет данные в URL. Вот краткая версия функции.

extension NSData {

    func writeToURL1(url:NSURL, completion: () -> Void)  {

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), { [weak self] in

            guard let strongSelf = self else { return }

            strongSelf.writeToURL(url, atomically: true)

            completion()
            })
    }
}

Вот как мы это используем:

var imageData = UIImageJPEGRepresentation(image, 0.8)
imageData?.writeToURL(someURL) { in ... }

Проблема, конечно, в том, если imageData освобождается до завершения операции записи strongSelf будет ноль и обработчик завершения никогда не будет вызван.

Есть два решения этой проблемы.

  1. Удалить [weak self] (т.е. иметь сильную ссылку на self в writeToURL1,
  2. ссылка imageData в блоке завершения (т.е. imageData?.writeToURL(someURL) { in imageData = nil ... })

Какой подход является более дружественным для Swift и какой подход выбрать?

Спасибо!

2 ответа

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

В вашем случае вы заботитесь о том, чтобы объект мог исчезнуть, потому что это означает, что вы не сможете его сохранить. Поскольку у вас нет гарантии, что что-то еще будет поддерживать объект до тех пор, пока эта задача не будет выполнена, вы должны использовать надежную ссылку.

Сильные ссылки на self в замыканиях возникает проблема, когда вы переносите замыкание, потому что легко получить неочевидный ссылочный цикл, но вы точно знаете, что ссылка будет отброшена сразу после выполнения замыкания, так что это не проблема,

Звучит так, будто вы просто хотите строго захватить ссылку на объект NSData, поэтому удаление [weak self] это самый простой и лучший подход на мой взгляд. Обычно слабые ссылки используются, чтобы избежать сохранения циклов при захвате в замыкании. Тем не менее, вы на самом деле не создаете цикл сохранения, просто один способ сохранения, захватывая себя в блоке. Блок не сохраняется самостоятельно, он просто передается по стеку вызовов в dispatch_async, где он в конечном счете вызывается и освобождается. Таким образом, нет никакого цикла сохранения, чтобы избежать с помощью weak selfУ вас просто есть удержание происходит через закрытие, что желательно. То есть вы хотите хранить данные в памяти до тех пор, пока не будет вызвано это закрытие.

Другие вопросы по тегам