Sobes.tech
Middle+

Ի՞նչ է խախտում ընտրովի գործառույթը պրոտոկոլում։

sobes.tech AI

Պատասխան AI-ից

Ավելացում պահանջների պրոտոկոլին այն բանից հետո, երբ այն սկսեցին օգտագործել այլ մոդուլներ կամ գրադարաններ: Եթե պրոտոկոլը արդեն ընդունված և իրականացված է, սովորական (չափազանցական) մեթոդների կամ հատկությունների ավելացումը կհանգեցնի կոդի սխալների բոլոր վայրերում, որտեղ օգտագործվում է պրոտոկոլը, մինչեւ նոր պահանջները կատարվեն:

Ընտրական պահանջները թույլ են տալիս ընդլայնել պրոտոկոլները, առանց գոյություն ունեցող իրականացմանը «վնասելու»: Կլասները կամ կառուցվածքները կարող են իրականացնել միայն մասամբ ընտրական մեթոդներ: Սա օգտակար է դելեգատորների հետ աշխատելիս կամ երբ ավելացվում են նոր ֆունկցիաներ արդեն կայացած API-ում:

Օրինակ՝ Objective-C-ում պրոտոկոլի ընտրական պահանջ (քանի որ Swift-ը չի աջակցում @optional առանց @objc):

// Swift-ում @optional-ը օգտագործվում է @objc պրոտոկոլի հետ
import Foundation

@objc protocol MyDelegate {
    func requiredMethod() -> Bool

    @optional func optionalMethod1()
    @optional func optionalMethod2(value: Int)
}

class MyClass {
    weak var delegate: MyDelegate?

    func doSomething() {
        if delegate?.requiredMethod() == true {
            // Կոչում ենք ընտրական մեթոդը ստուգմամբ
            delegate?.optionalMethod1?()

            if let delegate = delegate {
                if delegate.responds(to: #selector(delegate.optionalMethod2(value:))) {
                    delegate.optionalMethod2?(value: 10)
                }
            }
        }
    }
}

Swift-ում մաքուր պրոտոկոլները (առանց @objc) չեն աջակցում @optional-ին: Որպեսզի ունենաք ընտրական պահանջներ, պրոտոկոլը պետք է նշված լինի որպես @objc: Այդպիսի պրոտոկոլների իրականացմանը կարող են ավելացվել ընդլայնումներ՝ ընտրական մեթոդների իրականացման համար որպես նախնական, ինչը ավելի արդիական մոտեցում է Swift-ում:

Ստորև՝ Swift-ում պրոտոկոլների ընտրական վարքագիծը ընդլայնումների միջոցով՝

// Ավելի Swift-յան մոտեցում՝ պրոտոկոլների ընդլայնումներ՝ ըստ նախնական իրականացման
protocol MyProtocol {
    func requiredMethod() -> Bool
    func optionalMethod1()
    func optionalMethod2(value: Int)
}

// Առանցքային իրականացումներ՝ որպես «ընտրական» մեթոդներ
extension MyProtocol {
    func optionalMethod1() {
        // Նախնական իրականացում կամ ստանդարտ վարք
        print("Optional method 1 default implementation")
    }

    func optionalMethod2(value: Int) {
        // Նախնական իրականացում
        print("Optional method 2 default implementation with value: \(value)")
    }
}

class MyClassSwift {
    var delegate: MyProtocol?

    func doSomething() {
        if delegate?.requiredMethod() == true {
            // Կոչում ենք մեթոդները առանց ստուգման, քանի որ դրանք կամ իրականացնում են, կամ օգտագործում են ընդլայնումից
            delegate?.optionalMethod1()
            delegate?.optionalMethod2(value: 20)
        }
    }
}

class MyCustomDelegate: MyProtocol {
    func requiredMethod() -> Bool {
        print("Required method implemented")
        return true
    }

    // optionalMethod1() և optionalMethod2(value:) չեն պարտադիր իրականացնել, 
    // օգտագործվում է ընդլայնումից՝ նախնական իրականացում
    // Բայց կարող եք վերականգնել դրանք՝ եթե այլ վարք եք ուզում:
    // func optionalMethod1() {
    //     print("Custom implementation of optional method 1")
    // }
}

let customDelegate = MyCustomDelegate()
let myClassSwift = MyClassSwift()
myClassSwift.delegate = customDelegate
myClassSwift.doSomething()

Այսպիսով, պրոտոկոլում ընտրական ֆունկցիայի ավելացումը՝ փորձել ավելացնել նոր պարտադիր պահանջ՝ արդեն օգտագործվող պրոտոկոլում, խախտում է հակադարձ համատեղելիությունը: Ընտրական պահանջները (առանց @objc կամ՝ ավելի լավ՝ ընդլայնումների միջոցով) կանխում են այս խախտումը։