2016-04-24 3 views
4

Если у меня есть протокол:Swift ссылки протокола и слабый с классом

protocol SomeProtocol { 
    func doSomething() 
} 

и в вспомогательном классе, у меня есть ссылка на переменный протокол:

class someClass { 
    var delegate: SomeProtocol? 
} 

потому SomeProtocol не отмеченный : class, предполагается, что delegate может быть любым, и в случае типов значений (структур и перечислений) нет необходимости в weak var, потому что типы значений не могут создавать сильные ссылки. Фактически, компилятор не разрешает weak var ни на чем, кроме классов.

Однако ничто не мешает вам от создания класса в качестве делегата и, если протокол не помечен : class (как SomeProtocol is), слабой var` не могут быть использованы, и что создает цикл сохранения.

class MyClass: NSObject, SomeProtocol { 
    func doSomething() { } 
} 

struct MyStruct: SomeProtocol { 
    func doSomething() { } 
} 

let someClass = SomeClass() 
let myStruct = MyStruct() 
someClass.delegate = myStruct 
// After myStruct gets assigned to the delegate, do the delegate and the struct refer to the same instance or does the struct get copied?D 

let myClass = MyClass() 
someClass.delegate = myClass // can't use weak var so myClass is retained 

Приведенный выше пример, в случае использования делегатов и источника данных, не должен использоваться всегда : class? В принципе, любой протокол, который используется для ведения ссылки, должен всегда ограничиваться объектами класса?

+0

Я считаю, что только класс делегата/структура имеет слабую ссылку на делегата, а не на делегата, имеющего слабую ссылку на делегата. – tktsubota

+0

Я тоже так думал, но я узнал, когда создавал вспомогательный класс 'UICollectionView' со ссылкой на протокол, который не был помечен классом, где ссылка была на' UIViewController'. Поскольку протокол не был классом, свойство не могло быть «слабым» и никогда не было освобождено. – barndog

+0

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

ответ

1

Право. Если вы a пытаются сломать цикл сохранения со слабой ссылкой, вы должны использовать классы, потому что модификатор weak работает только с ссылочными типами (классами).

+0

Вы также можете разбить цикл сохранения, установив 'delegate = nil' в метод' deinit() ' –

+1

Нет, вы не можете, просто потому, что метод' deinit' не будет вызываться из-за цикла сохранения. –

+0

Я уточню в другом ответе. –

0

: class - предпочтительный подход в большинстве случаев. Однако в качестве альтернативного ответа вы можете установить delegate = nil в методе родительского объекта deinit.

Например, скажем, родительский объект является NSOperation подкласс, который имеет свойство SomeClass, и это свойство имеет делегат, который реализует SomeProtocol:

protocol SomeProtocol { 
    func doSomething() 
} 

class SomeClass { 
    var delegate: SomeProtocol? 
} 

class CustomOperation: NSOperation { 
    let foo: SomeClass 
} 

Мы сделаем класс, который реализует протокол также:

class SomeProtocolImplementation: SomeProtocol { 
    func doSomething() { 
     print("Hi!") 
    } 
} 

Теперь мы можем назначить foo в init():

class CustomOperation: NSOperation { 
    let foo: SomeClass 

    override init() { 
     foo = SomeClass() 
     foo.delegate = SomeProtocolImplementation() 
     super.init() 
    } 
} 

Это создает цикл удержания. Тем не менее, рассмотрим этот deinit метод:

deinit { 
     foo.delegate = nil 
    } 

Теперь, когда CustomOperation будут высвобождены, foo.delegate будет установлен в nil, нарушая цикл сохранения. Затем, когда пул авторецепции сливается в конце цикла запуска, оба SomeClass и SomeProtocolImplementation будут освобождены.

+1

Проблема с этой настройкой не создает цикл сохранения в первую очередь. Экземпляр «CustomOperation» имеет сильную ссылку на экземпляр «SomeClass», который имеет сильную ссылку на экземпляр «SomeProtocolImplementation». Это линейная линия, без циклов, поэтому цикл сохранения не сохраняется. Способ работы большинства делегатов (в вашем случае) 'foo.delegate = self', где' self' соответствует 'SomeProtocol'. В этом случае избежать цикла сохранения можно с помощью 'deinit', так как делегат и делегат будут поддерживать друг друга в живых. – Hamish

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