स्विफ्ट में विभिन्न प्रकार के साथ सुपरक्लास संपत्ति को ओवरराइड करना


129

स्विफ्ट में, क्या कोई समझा सकता है कि सुपरक्लास पर एक संपत्ति को कैसे ओवरराइड करना है मूल संपत्ति से उप-वर्गित किसी अन्य वस्तु के साथ?

इसका सरल उदाहरण लें:

class Chassis {}
class RacingChassis : Chassis {}

class Car {
    let chassis = Chassis()
}
class RaceCar: Car {
    override let chassis = RacingChassis() //Error here
}

यह त्रुटि देता है:

Cannot override with a stored property 'chassis'

यदि मेरे पास 'var' के रूप में चेसिस है, तो मुझे त्रुटि मिलती है:

Cannot override mutable property 'chassis' of type 'Chassis' with covariant type 'RacingChassis'

केवल एक चीज जो मुझे "ओवरराइडिंग प्रॉपर्टीज़" के तहत गाइड में मिल सकती है, यह दर्शाता है कि हमें गेट्टर और सेटर को ओवरराइड करना होगा, जो संपत्ति के मूल्य को बदलने के लिए काम कर सकता है (यदि यह 'var' है), लेकिन संपत्ति वर्ग को बदलने के बारे में क्या ?

जवाबों:


115

स्विफ्ट आपको किसी भी प्रकार या चर के वर्ग प्रकार को बदलने की अनुमति नहीं देता है। इसके बजाय आप नए वर्ग प्रकार को संभालने वाले उपवर्ग में एक अतिरिक्त चर बना सकते हैं:

class Chassis {}
class RacingChassis : Chassis {}

class Car {
    var chassis = Chassis()
}
class RaceCar: Car {
    var racingChassis = RacingChassis()
    override var chassis: Chassis {
        get {
            return racingChassis
        }
        set {
            if let newRacingChassis = newValue as? RacingChassis {
                racingChassis = newRacingChassis
            } else {
                println("incorrect chassis type for racecar")
            }
        }
    }
}

ऐसा लगता है कि कोई व्यक्ति सिंटैक्स के साथ एक संपत्ति की घोषणा नहीं कर सकता है और इसे उप-वर्ग या इसके विपरीत में var के साथ ओवरराइड कर सकता है, जो हो सकता है क्योंकि सुपरक्लास कार्यान्वयन शायद उस संपत्ति को एक बार शुरू करने के बाद बदलने की उम्मीद नहीं कर सकता है। तो इस मामले में संपत्ति को सुपरक्लास में 'var' के साथ-साथ उप-वर्ग (जैसा कि ऊपर स्निपेट में दिखाया गया है) से मिलान करने की आवश्यकता है। यदि कोई सुपरक्लास में स्रोत कोड को बदल नहीं सकता है, तो संभवतः वर्तमान रेसकार को नष्ट करने और चेसिस को म्यूट किए जाने की आवश्यकता के लिए हर बार एक नया रेसकार बनाने के लिए सबसे अच्छा है।


1
क्षमा करें, बस मेरी टिप्पणी को हटा दिया गया और फिर आपका उत्तर देखा। मुझे एक समस्या हो रही थी क्योंकि मेरे वास्तविक मामले में मेरा सुपरक्लास एक strongसंपत्ति के साथ एक उद्देश्य-सी वर्ग है और मुझे इसे ओवरराइड करने की कोशिश में एक त्रुटि मिल रही थी - लेकिन ऐसा लगता है कि मुझे याद आया कि यह "अनुमानित रूप से अलिखित वैकल्पिक" ( chassis!) में अनुवाद करता है। स्विफ्ट, इसलिए override var chassis : Chassis!इसे ठीक करता है।
जेम्स

4
यह अब Xcode 6.1 के तहत Swift 1.1 के साथ काम नहीं करता है। त्रुटि उत्पन्न करता है: "अपरिवर्तनीय 'चलो' संपत्ति 'चेसिस' को 'वर्जन' के गेट्टर से नहीं हटा सकते।" बेहतर समाधान के लिए कोई विचार?
डारर्सकी

1
इसके अलावा अब Xcode 6.3 बीटा के तहत स्विफ्ट 1.2 में काम नहीं करता है। सहसंयोजक प्रकार 'टाइप 2' के साथ 'टाइप 1' की उत्परिवर्तनीय संपत्ति को 'ए' से बाहर नहीं किया जा सकता है
बुबक्सु

10
यह वास्तव में लंगड़ा है, और स्विफ्ट की असफलता, इमो। चूंकि RacingChassis है एक चेसिस, संकलक आप एक उपवर्ग में संपत्ति का वर्ग को परिष्कृत करने के लिए अनुमति देता है कोई समस्या नहीं होनी चाहिए। बहुत सी भाषाएं इसे अनुमति देती हैं, और इसका समर्थन नहीं करने से इस तरह से बदसूरत वर्कअराउंड हो जाता है। कोई अपराध नहीं। : /
devios1

1
वैकल्पिक यह सुझाव देते हैं कि एक चर मौजूद नहीं हो सकता है क्योंकि यह एक फ़ंक्शन द्वारा प्रदान किया गया था जो अब अपेक्षित मूल्य नहीं देता है। ऐसे मामले हो सकते हैं यदि फ़ंक्शन को ओवरराइड किया गया था। विवरण के लिए मेरे उत्तर पर एक नज़र डालें।

10

यह काम करने लगता है

class Chassis {
    func description() -> String {
        return "Chassis"
    }
}
class RacingChassis : Chassis {
    override func description() -> String {
        return "Racing Chassis"
    }

    func racingChassisMethod() -> String {
        return "Wrooom"
    }
}

class Car {
    let chassis = Chassis()
}
class RaceCar: Car {
    override var chassis: RacingChassis {
    get {
        return self.chassis
    }
    set {
        self.chassis = newValue
    }
    }
}

var car = Car()
car.chassis.description()

var raceCar = RaceCar()
raceCar.chassis.description()
raceCar.chassis.racingChassisMethod()

1
यह चेसिस प्रॉपर्टी को क्लास letमें परिभाषित करने के रूप में काम करता है Carजो इसे बदलना असंभव बनाता है। हम केवल वर्ग chassisपर संपत्ति बदल सकते हैं RaceCar
डेविड आरव

4
यह स्विफ्ट 2.0 के लिए काम नहीं करता है। यह "त्रुटि देता है: अपरिवर्तनीय 'लेट' प्रॉपर्टी 'चेसिस' को '
वर्जन

यह स्विफ्ट 4.0 में भी काम नहीं करता है। लेफ़्टग्राउंड निष्पादन विफल: त्रुटि: MyPlaygrounds.playground: 14: 15: त्रुटि: अपरिवर्तनीय 'लेट' प्रॉपर्टी 'चेसिस' को ओवरराइड नहीं कर सकता, जिसमें 'var' ओवरराइड var चेसिस का गेट्टर हो: RacingChassel {^ MyPlaygrounds.playground: 11: 6: नोट: : यहाँ संपत्ति को ओवरराइड करने का प्रयास चेसिस = चेसिस () ^
करीम

7

इसे इस्तेमाल करे:

class Chassis{
     var chassis{
         return "chassis"
     } 
}

class RacingChassis:Chassis{
     var racing{
         return "racing"
     } 
}

class Car<Type:Chassis> {
     let chassis: Type
     init(chassis:Type){
        self.chassis = chassis
     }
}

class RaceCar: Car<RacingChassis> {
     var description{
         return self.chassis.racing
     } 
}

फिर:

let racingChassis = RacingChassis()
let raceCar = RaceCar(chassis:racingChassis)
print(raceCar.description) //output:racing

Http://www.mylonly.com/14957025459875.html पर विस्तार से


आह साफ और स्वच्छ
इंद्र कुमार राठौर

3

सॉल्यूशन डैश अच्छा काम करता है सिवाय इसके कि सुपर क्लास को वर की बजाय लेट कीवर्ड के साथ घोषित किया जाए। यहाँ एक समाधान है जो संभव है लेकिन जरूरी नहीं है!

नीचे दिए गए समाधान Xcode 6.2, SWIFT 1.1 (यदि सभी कक्षाएं अलग-अलग स्विफ्ट फ़ाइलों में हैं) के साथ संकलित किया जाएगा, लेकिन इसे टाला जाना चाहिए क्योंकि IT को UNHPECTED BEHAVIORS (विशेष रूप से गैर-वैकल्पिक प्रकारों का उपयोग करते हुए) शामिल किया जा सकता है। नोट: इस XCODE 6.3 बीटा 3, स्विफ्ट 1.2 के साथ काम नहीं करता है

class Chassis {}
class RacingChassis : Chassis {}
class Car {
    var chassis:Chassis? = Chassis()
}

class RaceCar: Car {
    override var chassis: RacingChassis? {
        get {
            return super.chassis as? RacingChassis
        }
        set {
            super.chassis = newValue
        }
    }
}

1
यह स्विफ्ट 2.0 के लिए काम नहीं करता है। यह "चेसिस के प्रकार 'की परस्पर संपत्ति को नष्ट नहीं कर सकता है? सहसंयोजी प्रकार के साथ 'रेसिंगचैसिस?' '
mohamede1945

2

सैद्धांतिक रूप से, आपको इसे इस तरह से करने की अनुमति है ...

class ViewController {

    var view: UIView! { return _view }

    private var _view: UIView!
}

class ScrollView : UIView {}

class ScrollViewController : ViewController {

    override var view: ScrollView! { return super.view as ScrollView! }
}

class HomeView : ScrollView {}

class HomeViewController : ScrollViewController {

    override var view: HomeView! { return super.view as HomeView! }
}

यह पूरी तरह से एक Xcode खेल के मैदान में काम करता है।

लेकिन , यदि आप इसे वास्तविक परियोजना में आज़माते हैं, तो संकलक त्रुटि आपको बताती है:

घोषणा 'दृश्य' एक से अधिक सुपरक्लास घोषणा को ओवरराइड नहीं कर सकता है

मैंने अब तक केवल Xcode 6.0 GM की जाँच की है।

दुर्भाग्य से, आपको Apple को इसे ठीक करने तक इंतजार करना होगा।

मैंने एक बग रिपोर्ट भी प्रस्तुत की है। 18518795


यह एक दिलचस्प समाधान है, और यह 6.1 में काम करता है।
क्रिस कॉनवर

1

मैंने बहुत सारे कारण देखे हैं कि फ़ंक्शन के बजाय वेरिएबल्स का उपयोग करके एपीआई को डिजाइन करना समस्याग्रस्त है और मेरे लिए गणना की गई संपत्तियों का उपयोग करके वर्कअराउंड की तरह महसूस होता है। आपके उदाहरण चर को संक्षिप्त रखने के लिए अच्छे कारण हैं। यहाँ मैंने एक प्रोटोकॉल ऑटोमोबाइल बनाया है जो कार के अनुरूप है। इस प्रोटोकॉल में एक एक्सेसर विधि है जो चेसिस ऑब्जेक्ट को लौटाती है। चूंकि कार इसके अनुरूप है, रेसकर उपवर्ग इसे ओवरराइड कर सकता है और एक अलग चेसिस उपवर्ग को वापस कर सकता है। यह कार वर्ग को एक इंटरफ़ेस (ऑटोमोबाइल) और रेसकार क्लास के लिए प्रोग्राम करने की अनुमति देता है जो कि रेसिंगचैसिस के बारे में जानता है कि _racingChassis चर को सीधे एक्सेस कर सकता है।

class Chassis {}
class RacingChassis: Chassis {}

protocol Automobile {
    func chassis() -> Chassis
}

class Car: Automobile {
    private var _chassis: Chassis

    init () {
        _chassis = Chassis()
    }

    func chassis() -> Chassis {
        return _chassis
    }
}

class RaceCar: Car {
    private var _racingChassis: RacingChassis

    override init () {
        _racingChassis = RacingChassis()
        super.init()
    }

    override func chassis() -> Chassis {
        return _racingChassis
    }
}

चर का उपयोग करके एपीआई को डिज़ाइन करने का एक और उदाहरण तब होता है जब आपके पास प्रोटोकॉल में चर होते हैं। यदि आप अपने द्वारा किए जा सकने वाले एक्सटेंशन में सभी प्रोटोकॉल फ़ंक्शंस को तोड़ना चाहते हैं, तो संग्रहीत संपत्तियों को एक्सटेंशन में नहीं रखा जा सकता है और उन्हें क्लास में परिभाषित किया जाना है (इसे संकलित करने के लिए आपको कोड को असहज करना होगा; AdaptableViewController वर्ग और विस्तार से मोड चर निकालें):

protocol Adaptable {
    var mode: Int { get set }
    func adapt()
}

class AdaptableViewController: UIViewController {
    // var mode = 0
}

extension AdaptableViewController: Adaptable {

    var mode = 0 // compiler error

    func adapt() {
        //TODO: add adapt code
    }
}

उपरोक्त कोड में यह संकलक त्रुटि होगी: "एक्सटेंशन में संग्रहीत गुण नहीं हो सकते हैं"। यहां बताया गया है कि आप ऊपर दिए गए उदाहरण को फिर से कैसे लिख सकते हैं ताकि प्रोटोकॉल में सब कुछ अलग-अलग किया जा सकता है इसके बजाय फ़ंक्शन का उपयोग करके:

protocol Adaptable {
    func mode() -> Int
    func adapt()
}

class AdaptableViewController: UIViewController {
}

extension AdaptableViewController: Adaptable {
    func mode() -> Int {
        return 0
    }
    func adapt() {
        // adapt code
    }
}

1

आप इसे जेनरिक के उपयोग से प्राप्त कर सकते हैं:

class Descriptor {
    let var1 = "a"
}

class OtherDescriptor: Descriptor {
    let var2 = "b"
}

class Asset<D: Descriptor> {
    let descriptor: D

    init(withDescriptor descriptor: D) {
        self.descriptor = descriptor
    }

    func printInfo() {
        print(descriptor.var1)
    }
}

class OtherAsset<D: OtherDescriptor>: Asset<D> {
    override func printInfo() {
        print(descriptor.var1, descriptor.var2)
    }
}

let asset = Asset(withDescriptor: Descriptor())
asset.printInfo() // a

let otherAsset = OtherAsset(withDescriptor: OtherDescriptor())
otherAsset.printInfo() // a b

इस दृष्टिकोण के साथ आपके पास 100% प्रकार के सुरक्षित कोड होंगे जो बिना किसी बल के होते हैं।

लेकिन यह एक तरह का हैक है, और अगर आपको क्लास की घोषणाओं की तुलना में कई संपत्तियों को फिर से परिभाषित करने की आवश्यकता होगी, तो यह कुल गड़बड़ जैसा होगा। इसलिए इस दृष्टिकोण से सावधान रहें।


1

आप संपत्ति का उपयोग कैसे करते हैं, इस पर निर्भर करते हुए, ऐसा करने का सबसे सरल तरीका अपने उपवर्ग के लिए एक वैकल्पिक प्रकार का उपयोग करना है, और didSet {}सुपर के लिए विधि को ओवरराइड करना है :

class Chassis { }
class RacingChassis: Chassis { }

class Car {
    // Declare this an optional type, and do your 
    // due diligence to check that it's initialized
    // where applicable
    var chassis: Chassis?
}
class RaceCar: Car {
    // The subclass is naturally an optional too
    var racingChassis: RacingChassis?
    override var chassis: Chassis {
        didSet {
            // using an optional, we try to set the type
            racingChassis = chassis as? RacingChassis
        }
    }
}

जाहिर है कि आपको यह सुनिश्चित करने के लिए कुछ समय बिताने की ज़रूरत है कि कक्षाएं इस तरह से शुरू की जा सकती हैं, लेकिन गुणों को वैकल्पिक रूप से सेट करके, आप खुद को उन परिस्थितियों से बचाते हैं, जहां अब काम नहीं करना है।


0

आप बस RacingChassis का एक और वेरिएबल बना सकते हैं।

class Chassis {}
class RacingChassis : Chassis {}
class Car {
    let chassis: Chassis
    init(){
        chassis = Chassis()
}}

class RaceCar: Car {
let raceChassis: RacingChassis
init(){
        raceChassis = RacingChassis()
}}

यह काम करता है, लेकिन मुझे लगता है कि डैश का जवाब ओवरराइड करके chassisऔर संपत्ति के RacingChassisसाथ अपना उदाहरण प्राप्त करने की अनुमति देकर इसे एक कदम आगे ले जाता chassisहै।
जेम्स

0

इसे इस्तेमाल करे:

class Chassis {}
class RacingChassis : Chassis {}
class SuperChassis : RacingChassis {}

class Car {
    private var chassis: Chassis? = nil
    func getChassis() -> Chassis? {
        return chassis
    }

    func setChassis(chassis: Chassis) {
        self.chassis = chassis
    }
}

class RaceCar: Car {
    private var chassis: RacingChassis {
        get {
            return getChassis() as! RacingChassis
        }
        set {
            setChassis(chassis: newValue)
        }
    }

    override init() {
        super.init()

        chassis = RacingChassis()
    }
}

class SuperCar: RaceCar {
    private var chassis: SuperChassis {
        get {
            return getChassis() as! SuperChassis
        }
        set {
            setChassis(chassis: newValue)
        }
    }

    override init() {
        super.init()

        chassis = SuperChassis()
    }
}

0
class Chassis {}
class RacingChassis : Chassis {}

class Car {
    fileprivate let theChassis: Chassis
    var chassis: Chassis {
        get {
            return theChassis
        }
    }
    fileprivate init(_ chassis: Chassis) {
        theChassis = chassis
    }
    convenience init() {
        self.init(Chassis())
    }
}
class RaceCar: Car {
    override var chassis: RacingChassis {
        get {
            return theChassis as! RacingChassis
        }
    }
    init() {
        super.init(RacingChassis())
    }
}

0

निम्नलिखित एक एकल वस्तु को आधार और व्युत्पन्न वर्गों में उपयोग करने की अनुमति देता है। व्युत्पन्न वर्ग में, व्युत्पन्न वस्तु संपत्ति का उपयोग करें।

class Car {
    var chassis:Chassis?

    func inspect() {
        chassis?.checkForRust()
    }
}

class RaceCar: Car {
    var racingChassis: RacingChassis? {
        get {
            return chassis as? RacingChassis
        } 
    }

    override func inspect() {
        super.inspect()
        racingChassis?.tuneSuspension()
    }
}

0

अन्य उत्तरों की थोड़ी भिन्नता, लेकिन कुछ अच्छे लाभों के साथ सरल और सुरक्षित।

class Chassis {}
class RacingChassis : Chassis {}

class Car {
    let chassis = Chassis()
}
class RaceCar: Car {
    var racingChassis: RacingChassis? {
        get {
            return chassis as? RacingChassis
        }
    }
}

लाभों में शामिल है कि चेसिस क्या होना चाहिए (var, let, वैकल्पिक, आदि) पर कोई प्रतिबंध नहीं है, और रेसकार को उप-वर्ग करना आसान है। रेसकार के उपवर्गों में चेसिस (या रेसिंगकैसिस) के लिए अपने स्वयं के गणना मूल्य हो सकते हैं।


-2

बस नए नामकरण संपत्ति को अलग नामकरण सम्मेलन के साथ सेट करें जैसे imgview क्योंकि imageView पहले से ही अपनी संपत्ति है और हम 2 मजबूत गुणों को असाइन नहीं कर सकते हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.