ყოველთვის საჭიროა weak ან unowned გამოყენება დაკავების სიაში?
sobes.tech AI
პასუხი AI-სგან
ხოლო, არა ყოველთვის.
გამოყენებულია weak ან unowned Capture List-ში, რათა თავიდან აიცილოს retain cycle-ები.
Retain cycle-ები წარმოიქმნება, როდესაც ორი ან მეტი ობიექტი ძლიერად მიმართავენ ერთმანეთს, რაც არ აძლევს მეხსიერების გათავისუფლებას.
გამოყენება weak ან unowned საჭიროა, როდესაც დახურვა ძლიერად მიმართავს self (ან სხვა კლასი/აკტორის მაგალითის ცვლადს), და თავის მხრივ self (ან სხვა ობიექტი) აქვს ძლიერი მიკერძოება ამ დახურვაზე.
მაგალითები სიტუაციების, სადაც ეს აუცილებელია:
- ასინქრონული ოპერაციები (სერვისის მოთხოვნები, მონაცემების დამუშავება)
- Observer პატერნი
- ანიმაციური ბლოკები
- Dispatch რიგები
თუ დახურვა არ იჭერს self (ან სხვა კლასი/აკტორის ცვლადს, რომელიც აქვს ძლიერი მიკერძოება დახურვაზე), ან იჭერს სტრუქტურული ტიპებს/სია, weak ან unowned გამოყენება საჭირო არ არის.
weak და unowned შორის განსხვავება:
| ტიპი | აღწერა | როდესაც გამოიყენება |
|---|---|---|
weak |
სუსტი (ოპციონალური) მიკერძოება. შეიძლება გახდეს nil. |
როდესაც დახურვის სიცოცხლის ციკლი მოკლეა ან თანაბარია იჭერით ობიექტის სიცოცხლის ციკლთან, და ობიექტი შეიძლება გახდეს nil დახურვის დასრულებამდე. |
unowned |
უქმნელი (ოპციონალური არა) მიკერძოება. არ შეიძლება გახდეს nil. |
როდესაც დახურვის სიცოცხლის ციკლი მოკლეა ან თანაბარია იჭერით ობიექტის სიცოცხლის ციკლთან, და გარანტირებული არის, რომ ობიექტი იქნება არსებობაში დახურვის დასრულებამდე. თუ ობიექტი გათავისუფლდა ადრე, მოხდება შეცდომა (unowned მიკერძოება deallocated instance-ზე). |
weak გამოყენების მაგალითი:
class MyClass {
var name: String = "Test"
func performAsyncOperation() {
DispatchQueue.global().async { [weak self] in
guard let self = self else {
return
}
print("ოპერაცია დასრულდა עבור \(self.name)")
}
}
deinit {
print("MyClass განულდა")
}
}
unowned გამოყენების მაგალითი:
class ViewController {
var dismissButton: UIButton!
func setupButton() {
dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
// ამ შემთხვევაში, დახურვა იჭერს `self`-ს.
// თუ ეს იქნებოდა დახურვა, მაგალითად, UIControl.Event-ის handler-ში,
// და ViewController-ის არსებობა გარანტირებულია, სანამ ღილაკზე დაწკაპუნება მოხდება:
// dismissButton.addAction(UIAction { [unowned self] _ in
// self.dismiss(animated: true, completion: nil)
// }, for: .touchUpInside)
}
@objc func dismiss() {
// დისპლეის კონტროლერი გაუქმება
}
}
თუ დახურვა არ ქმნის retain cycle-ს, weak ან unowned გამოყენება საჭირო არ არის და შეიძლება გამოიწვიოს ზედმეტი შემოწმებები (weak-ის შემთხვევაში) ან შესაძლო შეცდომები (unowned-ის შემთხვევაში).
მაგალითად, დახურვა, რომელიც არ იჭერს self-ს ან სხვა ობიექტს, რომლის ძლიერი მიკერძოება აქვს:
func fetchData(completion: @escaping (Data) -> Void) {
URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
guard let data = data else { return }
// აქ არ იჭერება `self` ან სხვა ობიექტები, რომლებიც შეიძლება გამოიწვიოს retain cycle.
completion(data)
}.resume()
}
ამ შემთხვევაში [weak self] ან [unowned self] გამოყენება საჭირო არ არის.