Middle
ყოველთვის უნდა მიუთითოთ `self` პარამეტრი დახურვებში?
sobes.tech AI
პასუხი AI-სგან
არა, ყოველთვის არა:
საჭიროა self-ის ცხადყოფა დახურულში მხოლოდ შემდეგ შემთხვევებში:
- არ-გაშლილ (non-escaping) დახურულში: ეს კომპილატორის მოთხოვნაა
self-ის აშკარად აღნიშვნისთვის. მიუხედავად იმისა, რომ захват ტექნიკურად არსებობს, ის ხდება ფუნქციის შიგნით და არ ქმნის ძლიერი მითითებების ციკლს. - გაშლილ (escaping) დახურულში, როდესაც
self-ის захватыვა იმპლიციტურად (implicit capture): თუ დახურული ფუნქცია გადის იმ ფუნქციის ფარგლებს, სადაც ის გამოაცხადა (მაგალითად, გადაეცემა ასინქრონულ ოპერაციას, ინახება თვისებაში და ა.შ.), და თქვენself-ს უხილავად აყვანთ, კომპილატორი მოითხოვსself-ის ცხადყოფას, რათა თავიდან აიცილოს ძლიერი მითითებების ციკლი.
ყველა სხვა შემთხვევებში (მაგალითად, weak self ან unowned self-ის სია გამოყენებით) self-ის მითითება საჭირო არაა, რადგან საკუთრების ურთიერთობა მკაფიო კონტროლირებულია.
მაგალითი:
class MyClass {
var value = 10
func doSomething() {
// არ-გაშლილ დახურულში - საჭიროა `self`
UIView.animate(withDuration: 0.3) {
self.value = 20
}
}
func fetchData(completion: @escaping (Result<String, Error>) -> Void) {
// გაშლილ დახურულში, სადაც `self`-ის აყვანა უხილავია - საჭიროა `self`
// ეს შეიძლება გამოიწვიოს ძლიერი მითითებების ციკლი, თუ `[weak self]` არ გამოიყენება
someAsyncOperation { data, error in
if let data = data {
// საჭიროა `self` უხილავი აყვანით
self.processData(data)
completion(.success("Data processed"))
} else if let error = error {
completion(.failure(error))
}
}
}
func უსაფრთხოFetchData(completion: @escaping (Result<String, Error>) -> Void) {
// გაშლილ დახურულში, `[weak self]`-ით - `self?` ოპციონალურია და არ საჭიროებს `self.`-ის გამოყოფას
someAsyncOperation { [weak self] data, error in
guard let self = self else { return } // `self`-ის გახსნა ოპციონალურია
if let data = data {
self.processData(data) // `self.`-ის გამოყენება საჭირო არაა
completion(.success("Data processed"))
} else if let error = error {
completion(.failure(error))
}
}
}
private func processData(_ data: String) {
print("Processing \(data)")
}
}
func someAsyncOperation(completion: @escaping (String?, Error?) -> Void) {
// ასინქრონული ოპერაციის იმიტაცია
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
completion("Some data", nil)
}
}