Sobes.tech
Middle

Jak zabránit vzniku cyklu udržení (retain cycle) v iOS?

sobes.tech AI

Odpověď od AI

Cyklusy udržení jsou předcházeny správným použitím slabých (weak) nebo nepodmíněných (unowned) odkazů.

Slabé odkazy (weak):

  • nezvyšují počítadlo odkazů objektu.
  • mohou být nil (nullable).
  • používají se, když objekt může existovat nezávisle na jiném (například delegát).
class DelegateExample {
    weak var delegate: SomeDelegateType? // Slabý odkaz na delegáta
}

Nepodmíněné unowned odkazy (unowned):

  • nezvyšují počítadlo odkazů objektu.
  • jsou garantovaně nenulové (non-nil).
  • používají se, když jeden objekt výslovně vlastní jiný, ale závislý objekt může existovat pouze spolu s vlastníkem (například, uzávěry, které zachycují self ve třídě, kde uzávěr "patří" výslovně instanci třídy). Přístup k unowned odkazu, když je objekt již uvolněn, způsobí runtime chybu.
class Owner {
    var closure: (() -> Void)?

    func setupClosure() {
        closure = { [unowned self] in // Nepodmíněný `unowned` odkaz na self
            // Použití self
            print("Použití unowned self")
        }
    }
}

Použití v uzávěrech: Uzávěry mohou vytvářet cykly udržení, pokud zachycují instance tříd silnými odkazy, a tato instance třídy také obsahuje silnou odkaz na uzávěr. Aby se tomu zabránilo, používají se seznamy zachycení (capture lists) na začátku uzávěru:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [weak self] in // Slabý odkaz na self
        guard let strongSelf = self else {
            return "" // Ošetření případu, kdy je self již nil
        }
        if let text = strongSelf.text {
            return "<\(strongSelf.name)>\(text)</\(strongSelf.name)>"
        } else {
            return "<\(strongSelf.name)/>"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) je uvolněn")
    }
}

Volba mezi weak a unowned závisí na sémantice vztahů mezi objekty:

  • weak: když odkaz může během životního cyklu objektu, na který odkazuje, být nil.
  • unowned: když referencovaný objekt existuje garantovaně déle nebo stejně dlouho jako objekt, který na něj odkazuje, a odkaz nikdy nebude nil.