स्विफ्ट में केवल-और गैर-कंप्यूटेड वैरिएबल गुण


126

मैं नई Apple स्विफ्ट भाषा के साथ कुछ जानने की कोशिश कर रहा हूं। मान लीजिए कि मैं ऑब्जेक्टिव-सी में निम्नलिखित की तरह कुछ करता था। मेरे पास readonlyगुण हैं, और वे व्यक्तिगत रूप से नहीं बदले जा सकते हैं। हालांकि, एक विशिष्ट विधि का उपयोग करके, गुणों को तार्किक तरीके से बदल दिया जाता है।

मैं निम्नलिखित उदाहरण लेता हूं, एक बहुत ही सरल घड़ी। मैं इसे Objective-C में लिखूंगा।

@interface Clock : NSObject

@property (readonly) NSUInteger hours;
@property (readonly) NSUInteger minutes;
@property (readonly) NSUInteger seconds;

- (void)incrementSeconds;

@end

@implementation Clock

- (void)incrementSeconds {
     _seconds++;

     if (_seconds == 60) {
        _seconds = 0;
        _minutes++;

         if (_minutes == 60) {
            _minutes = 0;
            _hours++;
        }
    }
}

@end

एक विशिष्ट उद्देश्य के लिए, हम सेकंड, मिनट और घंटे को सीधे नहीं छू सकते हैं, और इसे केवल एक विधि का उपयोग करके सेकंड में वृद्धि करने की अनुमति है। केवल यह विधि उदाहरण चर की चाल का उपयोग करके मूल्यों को बदल सकती है।

चूंकि स्विफ्ट में इस तरह की चीजें नहीं हैं, इसलिए मैं एक समकक्ष खोजने की कोशिश कर रहा हूं। अगर मैं ऐसा करता हूं:

class Clock : NSObject {

    var hours:   UInt = 0
    var minutes: UInt = 0
    var seconds: UInt = 0

    func incrementSeconds() {

        self.seconds++

        if self.seconds == 60 {

            self.seconds = 0
            self.minutes++

            if self.minutes == 60 {

                self.minutes = 0
                self.hours++
            }
        }
    }
}

यह काम करेगा, लेकिन कोई भी सीधे गुण बदल सकता है।

हो सकता है कि मेरा पहले से ही Objective-C में ख़राब डिज़ाइन था और इसीलिए संभावित नई Swift समतुल्य नहीं है। यदि किसी के पास उत्तर नहीं है और मैं बहुत आभारी हूं;)

हो सकता है कि भविष्य में Apple द्वारा वादा किया गया एक्सेस कंट्रोल मैकेनिज्म इसका जवाब हो?

धन्यवाद!


2
एक्सेस कंट्रोल इसका जवाब है। आप वास्तविक डेटा के लिए निजी संपत्तियों का उपयोग करते हुए आसानी से गणना किए गए गुण बनाएंगे।
लियो नटन

Apple को यह बताने के लिए बग रिपोर्ट (एन्हांसमेंट) खोलना सुनिश्चित करें कि यह कितना गायब है।
सिंह राशि

1
नए उपयोगकर्ताओं के लिए: नीचे स्क्रॉल करें ...
Gustaf Rosenblad

2
कृपया @ एथन के उत्तर को सही मानें।
फतमान

जवाबों:


356

संपत्ति की घोषणा को उपसर्ग के साथ private(set), जैसे:

public private(set) var hours:   UInt = 0
public private(set) var minutes: UInt = 0
public private(set) var seconds: UInt = 0

privateइसे स्रोत फ़ाइल में internalस्थानीय रखता है , जबकि इसे मॉड्यूल / प्रोजेक्ट के लिए स्थानीय रखता है।

private(set)एक read-onlyसंपत्ति बनाता है , जबकि privateदोनों के लिए, setऔर getनिजी सेट करता है ।


28
"निजी" यह एक स्रोत फ़ाइल के लिए स्थानीय रखने के लिए, "आंतरिक" मॉड्यूल / परियोजना के लिए स्थानीय रखने के लिए। निजी (सेट) केवल सेट को निजी बनाता है। निजी दोनों सेट करता है और कार्यों को निजी बनाता है
user965972

3
इस उत्तर को और पूर्ण बनाने के लिए पहली टिप्पणी को जोड़ा जाना चाहिए।
रॉब नॉरबैक

अभी (स्विफ्ट 3.0.1) एक्सेस कंट्रोल लेवल बदल गए: "फाइलपाइरिट" घोषणा को केवल उसी सोर्स फाइल में कोड द्वारा घोषणा के रूप में एक्सेस किया जा सकता है। "निजी" घोषणा को केवल घोषणा के तत्काल घेरने के दायरे में कोड द्वारा पहुँचा जा सकता है।
जुरासिक

20

आप जो चाहते हैं, उसे करने के दो मूल तरीके हैं। पहला तरीका निजी संपत्ति और सार्वजनिक गणना वाली संपत्ति है, जो उस संपत्ति को लौटाती है:

public class Clock {

  private var _hours = 0

  public var hours: UInt {
    return _hours
  }

}

लेकिन इस, एक अलग, छोटे रास्ते में प्राप्त किया जा सकता के रूप में खंड में कहा गया है "अभिगम नियंत्रण" के "स्विफ्ट प्रोग्रामिंग भाषा" पुस्तक:

public class Clock {

    public private(set) var hours = 0

}

एक साइड नोट के रूप में, आपको सार्वजनिक प्रकार की घोषणा करते समय एक सार्वजनिक आरंभीक प्रदान करना होगा। यहां तक ​​कि अगर आप सभी गुणों के लिए डिफ़ॉल्ट मान प्रदान करते हैं, तो init()स्पष्ट रूप से सार्वजनिक रूप से परिभाषित किया जाना चाहिए:

public class Clock {

    public private(set) var hours = 0

    public init() {
      hours = 0
    }
    // or simply `public init() {}`

}

डिफ़ॉल्ट आरंभीकरण के बारे में बात करते समय, यह पुस्तक के उसी भाग में भी समझाया गया है।


5

चूंकि कोई एक्सेस कंट्रोल नहीं हैं (इसका अर्थ है कि आप एक एक्सेस कॉन्ट्रैक्ट नहीं बना सकते हैं जो कि कॉलर कौन है, इसके आधार पर अलग-अलग है), यहां मैं अभी के लिए क्या करूंगा:

class Clock {
    struct Counter {
        var hours = 0;
        var minutes = 0;
        var seconds = 0;
        mutating func inc () {
            if ++seconds >= 60 {
                seconds = 0
                if ++minutes >= 60 {
                    minutes = 0
                    ++hours
                }
            }
        }
    }
    var counter = Counter()
    var hours : Int { return counter.hours }
    var minutes : Int { return counter.minutes }
    var seconds : Int { return counter.seconds }
    func incrementTime () { self.counter.inc() }
}

यह केवल अप्रत्यक्ष के स्तर को जोड़ता है, जैसा कि काउंटर तक सीधे पहुंच के लिए था; एक अन्य वर्ग एक घड़ी बना सकता है और फिर सीधे उसके काउंटर तक पहुंच सकता है। लेकिन यह विचार - यानी, जिस अनुबंध को हम बनाने की कोशिश कर रहे हैं - वह यह है कि किसी अन्य वर्ग को केवल क्लॉक के शीर्ष-स्तरीय गुणों और विधियों का उपयोग करना चाहिए। हम उस अनुबंध को लागू नहीं कर सकते , लेकिन वास्तव में उद्देश्य-सी में भी लागू करना बहुत असंभव था।


ऐसा लगता है कि तब से बदल गया है, सही है? डेवलपर
.apple.com/swift/blog/?id=

1
@ यार, यह पूरा सवाल / जवाब स्विफ्ट में जुड़ने से बहुत पहले लिखा गया था। और स्विफ्ट अभी भी विकसित हो रहा है, इसलिए उत्तर पुराना हो जाएगा।
मैट

2

वास्तव में एक्सेस कंट्रोल (जो स्विफ्ट में अभी तक मौजूद नहीं है) लागू नहीं है जैसा कि आप ऑब्जेक्टिव सी में सोच सकते हैं । लोग आपके रीडायनली वैरिएबल को सीधे संशोधित कर सकते हैं, अगर वे वास्तव में चाहते हैं। वे सिर्फ कक्षा के सार्वजनिक इंटरफ़ेस के साथ ऐसा नहीं करते हैं।

आप स्विफ्ट में कुछ ऐसा कर सकते हैं (अपने कोड में कटौती और पेस्ट करें, साथ ही कुछ संशोधन, मैंने इसका परीक्षण नहीं किया है):

class Clock : NSObject {

    var _hours:   UInt = 0
    var _minutes: UInt = 0
    var _seconds: UInt = 0

    var hours: UInt {
    get {
      return _hours
    }
    }

    var minutes: UInt {
    get {
      return _minutes
    }
    }

    var seconds: UInt  {
    get {
      return _seconds
    }
    }

    func incrementSeconds() {

        self._seconds++

        if self._seconds == 60 {

            self._seconds = 0
            self._minutes++

            if self._minutes == 60 {

                self._minutes = 0
                self._hours++
            }
        }
    }
}

जो कि आपके पास ऑब्जेक्टिव C के समान है, सिवाय इसके कि वास्तविक संग्रहीत गुण सार्वजनिक इंटरफ़ेस में दिखाई देते हैं।

स्विफ्ट में आप कुछ और रोचक भी कर सकते हैं, जिसे आप ऑब्जेक्टिव C में भी कर सकते हैं, लेकिन यह शायद स्विफ्ट (ब्राउज़र में एडिट किया हुआ है, मैंने इसे टेस्ट नहीं किया है):

class Clock : NSObject {

    var hours: UInt = 0

    var minutes: UInt {
    didSet {
      hours += minutes / 60
      minutes %= 60
    }
    }

    var seconds: UInt  {
    didSet {
      minutes += seconds / 60
      seconds %= 60
    }
    }

    // you do not really need this any more
    func incrementSeconds() {
        seconds++
    }
}

"लोग आपके पठनीय चर को सीधे संशोधित कर सकते हैं" - आपका वास्तव में क्या मतलब है? कैसे?
user1244109

मैं ऑब्जेक्टिव सी का जिक्र कर रहा था। ऑब्जेक्टिव सी में आपको ऑब्जेक्टिव सी रनटाइम एपीआई के माध्यम से क्लास के बारे में हर चीज की डायनेमिक एक्सेस है।
एनालॉग फ़ाइल

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