संपत्ति मिलती है और बसती है


194

इस साधारण वर्ग के साथ मुझे कंपाइलर की चेतावनी मिल रही है

xअपने स्वयं के सेटर / गेटटर के भीतर संशोधित / उपयोग करने का प्रयास

और जब मैं इसे इस तरह उपयोग करता हूं:

var p: point = Point()
p.x = 12

मुझे एक EXC_BAD_ACCESS मिलता है। मैं स्पष्ट बैकिंग आइवर के बिना यह कैसे कर सकता हूं?

class Point {

    var x: Int {
        set {
            x = newValue * 2 //Error
        }
        get {
            return x / 2 //Error
        }
    }
    // ...
}

1
ऐसा करने से कंपाइलर पर अतिरिक्त भार भी पड़ेगा और सीपीयू की सख्ती से खपत होगी। मैंने बस यही किया: | । यह वह त्रुटि थी जो मैं बना रहा था। (मैं खेल के मैदान का उपयोग कर रहा था)
हनी

यह व्यवहार भ्रमित करने वाला है, बजाय इसके setकि आप उपयोग करना चाहते हैं didSet। गुण जब आप लागू करते हैं तो उद्देश्य-सी या अन्य भाषाओं की तुलना में स्विफ्ट में अलग व्यवहार करते हैं set@Jack से नीचे का उत्तर देखें और @cSquirrel से एक उदाहरणdidSet
पॉल सोल्ट

जवाबों:


232

सेटर्स और गेटर्स लागू होते हैं computed properties; इस तरह की संपत्तियों में उदाहरण के लिए भंडारण नहीं है - गेटर से मूल्य का मतलब अन्य उदाहरण गुणों से गणना करना है। आपके मामले में, xअसाइन नहीं किया जाना है।

स्पष्ट रूप से: "मैं स्पष्ट बैकिंग आइवर्स के बिना यह कैसे कर सकता हूं"। आप नहीं कर सकते हैं - आपको गणना की गई संपत्ति का बैकअप लेने के लिए कुछ की आवश्यकता होगी । इसे इस्तेमाल करे:

class Point {
  private var _x: Int = 0             // _x -> backingX
  var x: Int {
    set { _x = 2 * newValue }
    get { return _x / 2 }
  }
}

विशेष रूप से, स्विफ्ट REPL में:

 15> var pt = Point()
pt: Point = {
  _x = 0
}
 16> pt.x = 10
 17> pt
$R3: Point = {
  _x = 20
}
 18> pt.x
$R4: Int = 10

106

स्विफ्ट में सेटर्स / गेट्स ओबीजीसी से काफी अलग हैं। संपत्ति एक गणना की गई संपत्ति बन जाती है, जिसका अर्थ है कि यह ओबीसी में बैकिंग वैरिएबल नहीं है जैसे _xकि यह होगा।

समाधान कोड में आप देख सकते हैं नीचे xTimesTwoहै नहीं कुछ भी स्टोर, लेकिन बस की गणना से परिणाम x

गणना की गई संपत्तियों पर आधिकारिक डॉक्स देखें ।

आप जो कार्यक्षमता चाहते हैं, वह संपत्ति पर्यवेक्षक भी हो सकती है ।

आपको क्या चाहिए:

var x: Int

var xTimesTwo: Int {
    set {
       x = newValue / 2
    }
    get {
        return x * 2
    }
}

आप सेटर / गेटर्स के भीतर अन्य संपत्तियों को संशोधित कर सकते हैं, जो कि उनके लिए है।


1
हाँ, यही मैं प्रलेखन में पढ़ रहा हूँ। मैं संपत्ति अनुभाग पर छोड़ दिया और ऐसा लगता है कि इस के आसपास कोई रास्ता नहीं है, है ना?
एटमिक्स

हां, यदि आपको वास्तव में ऐसा करना है तो आपको पहले वाले "बैक" के लिए एक और उदाहरण चर की आवश्यकता होगी। हालांकि, बसने वाले इस उद्देश्य के लिए नहीं हैं, आपको शायद यह सोचना चाहिए कि आप इसे पूरा करने के लिए क्या प्रयास कर रहे हैं।
जैक

5
आप उपयोग कर सकते हैं didSetजो आपको सेट होने के तुरंत बाद मूल्य बदलने की अनुमति देगा। हालांकि पाने के लिए कुछ भी नहीं ...
ObjectiveCsam

1
नोट: यदि आप अमान्य इनपुट के कारण मान वापस करना चाहते हैं, तो आपको xवापस इसमें सेट करना oldValueहोगा didSet। व्यवहार में यह परिवर्तन, उद्देश्य-सी गुणों से आने वाली बहुत भ्रामक है, धन्यवाद!
पॉल सोल्ट

105

आप संपत्ति पर्यवेक्षक का उपयोग करके सेट मान को अनुकूलित कर सकते हैं। यह करने के लिए 'सेट' के बजाय 'डिडसेट' का उपयोग करें।

class Point {

var x: Int {
    didSet {
        x = x * 2
    }
}
...

पाने के लिए ...

class Point {

var doubleX: Int {
    get {
        return x / 2
    }
}
...

आप xइस पैटर्न में एक डिफ़ॉल्ट मान के साथ कैसे आरंभ कर सकते हैं ?
I_am_jorf

3
मैं देख रहा हूँ, यह होगा var x: Int = 0 { didSet { ...:।
I_am_jorf

31

GoZoner के जवाब पर विस्तृत करने के लिए:

यहाँ आपका असली मुद्दा यह है कि आप पुनरावर्ती को अपना गेटर कह रहे हैं।

var x:Int
    {
        set
        {
            x = newValue * 2 // This isn't a problem
        }
        get {
            return x / 2 // Here is your real issue, you are recursively calling 
                         // your x property's getter
        }
    }

जैसा कि ऊपर दी गई कोड टिप्पणी से पता चलता है, आप असीम रूप से x प्रॉपर्टी के गेट्टर को कॉल कर रहे हैं, जो तब तक निष्पादित होता रहेगा जब तक कि आपको EXC_BAD_ACCESS कोड नहीं मिलता (आप अपने Xcode के खेल के वातावरण के निचले दाएं कोने में स्पिनर को देख सकते हैं)।

स्विफ्ट प्रलेखन से उदाहरण पर विचार करें :

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

ध्यान दें कि कैसे केंद्र की गई संपत्ति कभी भी संशोधित नहीं होती है या चर की घोषणा में खुद को वापस नहीं लाती है।


अंगूठे का नियम कभी भी प्रापक के भीतर से संपत्ति का उपयोग नहीं करता है get। क्योंकि getजो दूसरे को ट्रिगर करेगा जो दूसरे को ट्रिगर करेगा। । । इसे प्रिंट भी न करें। क्योंकि मुद्रण को प्रिंट करने से पहले मूल्य प्राप्त करने की भी आवश्यकता होती है!
हनी

19

ओवरराइड setterऔर getterस्विफ्ट चर के लिए नीचे दिए गए कोड का उपयोग करें

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

हमें चर के मूल्य को एक अस्थायी चर में रखने की आवश्यकता है, क्योंकि उसी चर का उपयोग करने का प्रयास किया जा रहा है जिसके गेटटर / सेटर को ओवरराइड किया जा रहा है, जिसके परिणामस्वरूप अनंत लूप होंगे।

हम बस इस तरह सेटर को लागू कर सकते हैं

x = 10

कोड की दी गई रेखा के नीचे फायरिंग करने पर गेटक को मंगाया जाएगा

var newVar = x

8

आप कर रहे हैं रिकर्सिवली को परिभाषित करने xके साथ x। जैसे कि कोई आपसे पूछे कि आप कितने साल के हैं? और आप जवाब देते हैं "मैं अपनी उम्र से दोगुना हूं"। जो निरर्थक है।

आपको कहना चाहिए कि मैं जॉन की उम्र से दोगुना या किसी अन्य चर पर हूं लेकिन मैं खुद हूं ।

गणना किए गए चर हमेशा दूसरे चर पर निर्भर होते हैं।


अंगूठे का नियम कभी भी प्रापक के भीतर से संपत्ति का उपयोग नहीं करता है get। क्योंकि getजो दूसरे को ट्रिगर करेगा जो दूसरे को ट्रिगर करेगा। । । इसे प्रिंट भी न करें। क्योंकि मुद्रण को प्रिंट करने से पहले मूल्य प्राप्त करने की भी आवश्यकता होती है!

struct Person{
    var name: String{
        get{
            print(name) // DON'T do this!!!!
            return "as"
        }
        set{
        }
    }
}

let p1 = Person()

जैसा कि निम्नलिखित चेतावनी देगा:

इसके भीतर से 'नाम' तक पहुँचने की कोशिश की जा रही है।

त्रुटि इस तरह अस्पष्ट दिखती है:

यहां छवि विवरण दर्ज करें

एक विकल्प के रूप में आप उपयोग करना चाह सकते हैं didSet। इससे didSetआपको उस मूल्य पर एक पकड़ मिलेगी जो पहले सेट की गई थी और अभी सेट हो गई है। अधिक के लिए यह उत्तर देखें ।


8

अपडेट: स्विफ्ट 4

नीचे वर्ग में सेटर और गेट्टर को चर पर लागू किया जाता है sideLength

class Triangle: {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) { //initializer method
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get { // getter
            return 3.0 * sideLength
        }
        set(newValue) { //setter
            sideLength = newValue / 4.0
        }
   }

वस्तु बनाना

var triangle = Triangle(sideLength: 3.9, name: "a triangle")

प्राप्त करनेवाला

print(triangle.perimeter) // invoking getter

बैठानेवाला

triangle.perimeter = 9.9 // invoking setter

6

इसका उपयोग करके देखें:

var x:Int!

var xTimesTwo:Int {
    get {
        return x * 2
    }
    set {
        x = newValue / 2
    }
}

यह मूल रूप से जैक वू का जवाब है, लेकिन अंतर यह है कि जैक वू के जवाब में उसका एक्स वेरिएबल है var x: Int, मेरा है, मेरा एक्स वेरिएबल इस तरह है: var x: Int!इसलिए, मैंने जो किया वह सब एक वैकल्पिक प्रकार था।


1

स्विफ्ट 5.1 के लिए अपडेट

स्विफ्ट 5.1 के रूप में आप अब उपयोग किए बिना अपने चर प्राप्त कर सकते हैं प्राप्त कीवर्ड। उदाहरण के लिए:

var helloWorld: String {
"Hello World"
}

अगर मैं बदलने की कोशिश करता हूं, तो helloWorld = "macWorld" , मान को असाइन नहीं कर सकता: 'helloWorld' एक गेट-ओनली प्रॉपर्टी एरर दिखा रहा है।
McDonal_11

क्या नए मूल्यों को निर्दिष्ट करना संभव है? याँ नहीं ?
McDonal_11

मुझे नहीं लगता कि यह संभव है।
अतलयसा

तो साक्षर, var helloWorld: स्ट्रिंग {"हैलो वर्ल्ड"} और, helloWorld: स्ट्रिंग = "हैलो वर्ल्ड" समान हैं?
McDonal_11

हां मुझे ऐसा लगता है।
अतलय्यासा

0

स्विफ्ट में सेटर्स और गेटर्स परिकलित संपत्तियों / चर पर लागू होते हैं। ये गुण / चर वास्तव में स्मृति में संग्रहीत नहीं किए जाते हैं, बल्कि संगृहीत गुणों / चर के मूल्य के आधार पर गणना की जाती है।

इस विषय पर Apple के स्विफ्ट प्रलेखन देखें: स्विफ्ट परिवर्तनीय घोषणाएँ


0

यहाँ एक सैद्धांतिक जवाब है। वह यहां पाया जा सकता है

एक {get set} संपत्ति एक स्थिर संग्रहीत संपत्ति नहीं हो सकती है। यह एक कंप्यूटेड प्रॉपर्टी होनी चाहिए और सेट और दोनों को लागू किया जाना चाहिए।

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