Objective-C Language
मुख्य मूल्य कोडिंग / कुंजी मूल्य अवलोकन
खोज…
सबसे आम वास्तविक जीवन कुंजी मूल्य कोडिंग उदाहरण
कुंजी मान कोडिंग NSKeyValueCoding प्रोटोकॉल का उपयोग करके NSObject में एकीकृत है।
इसका क्या मतलब है?
इसका मतलब यह है कि कोई भी id ऑब्जेक्ट valueForKey मेथड और इसके विभिन्न वेरिएंट जैसे valueForKeyPhaar आदि को कॉल करने में सक्षम है।
इसका अर्थ यह भी है कि कोई भी आईडी ऑब्जेक्ट सेटवैल्यू पद्धति और उसके विभिन्न प्रकारों को भी लागू कर सकता है।
उदाहरण:
id obj = [[MyClass alloc] init];
id value = [obj valueForKey:@"myNumber"];
int myNumberAsInt = [value intValue];
myNumberAsInt = 53;
[obj setValue:@(myNumberAsInt) forKey:@"myNumber"];
अपवाद:
उपरोक्त उदाहरण मानता है कि MyClass में एक NSNumber प्रॉपर्टी है, जिसे MyNumber कहा जाता है। यदि MyNumber MyClass इंटरफ़ेस परिभाषा में प्रकट नहीं होता है, तो NSUndefinedKeyException को संभवतः दोनों लाइनों 2 और 5 पर उठाया जा सकता है - लोकप्रिय रूप से जाना जाता है:
this class is not key value coding-compliant for the key myNumber.
यह SO शक्तिशाली क्यों है:
आप उस वर्ग के गुणों की आवश्यकता के बिना कोड लिख सकते हैं जो किसी कक्षा के गुणों को गतिशील रूप से एक्सेस कर सकता है। इसका मतलब यह है कि एक तालिका दृश्य किसी NSObject व्युत्पन्न वस्तु के किसी भी गुण से मान प्रदर्शित कर सकता है, बशर्ते इसकी संपत्ति के नाम गतिशील रूप से रनटाइम पर आपूर्ति किए जाते हैं।
ऊपर दिए गए उदाहरण में, कोड माईक्लास के बिना भी काम कर सकता है और आईडी प्रकार obj को कॉलिंग कोड उपलब्ध है।
मुख्य मान
महत्वपूर्ण मान की स्थापना करना।
इस मामले में, हम ऐसी contentOffset
का निरीक्षण करना चाहते हैं, जो हमारे पर्यवेक्षक के पास है
//
// Class to observe
//
@interface XYZScrollView: NSObject
@property (nonatomic, assign) CGPoint contentOffset;
@end
@implementation XYZScrollView
@end
//
// Class that will observe changes
//
@interface XYZObserver: NSObject
@property (nonatomic, strong) XYZScrollView *scrollView;
@end
@implementation XYZObserver
// simple way to create a KVO context
static void *XYZObserverContext = &XYZObserverContext;
// Helper method to add self as an observer to
// the scrollView's contentOffset property
- (void)addObserver {
// NSKeyValueObservingOptions
//
// - NSKeyValueObservingOptionNew
// - NSKeyValueObservingOptionOld
// - NSKeyValueObservingOptionInitial
// - NSKeyValueObservingOptionPrior
//
// can be combined:
// (NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
NSString *keyPath = NSStringFromSelector(@selector(contentOffset));
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew;
[self.scrollView addObserver: self
forKeyPath: keyPath
options: options
context: XYZObserverContext];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if (context == XYZObserverContext) { // check the context
// check the keyPath to see if it's any of the desired keyPath's.
// You can observe multiple keyPath's
if ([keyPath isEqualToString: NSStringFromSelector(@selector(contentOffset))]) {
// change dictionary keys:
// - NSKeyValueChangeKindKey
// - NSKeyValueChangeNewKey
// - NSKeyValueChangeOldKey
// - NSKeyValueChangeIndexesKey
// - NSKeyValueChangeNotificationIsPriorKey
// the change dictionary here for a CGPoint observation will
// return an NSPoint, so we can take the CGPointValue of it.
CGPoint point = [change[NSKeyValueChangeNewKey] CGPointValue];
// handle point
}
} else {
// if the context doesn't match our current object's context
// we want to pass the observation parameters to super
[super observeValueForKeyPath: keyPath
ofObject: object
change: change
context: context];
}
}
// The program can crash if an object is not removed as observer
// before it is dealloc'd
//
// Helper method to remove self as an observer of the scrollView's
// contentOffset property
- (void)removeObserver {
NSString *keyPath = NSStringFromSelector(@selector(contentOffset));
[self.scrollView removeObserver: self forKeyPath: keyPath];
}
@end
केवीसी डेटा को छोड़कर
if ([[dataObject objectForKey:@"yourVariable"] isEqualToString:"Hello World"]) {
return YES;
} else {
return NO;
}
केवीसी का उपयोग करके संग्रहीत मूल्यों को आप जल्दी और आसानी से क्वेरी कर सकते हैं, उन्हें स्थानीय चर के रूप में पुनः प्राप्त करने या डालने की आवश्यकता के बिना।
संग्रह संचालक
संग्रह संचालकों का उपयोग "संग्रह-प्रकार" संपत्ति (यानी NSArray
, NSSet
और इसी तरह) पर एक ऑपरेशन करने के लिए KVC कुंजी पथ में किया जा सकता है। उदाहरण के लिए, प्रदर्शन करने के लिए एक सामान्य ऑपरेशन वस्तुओं को एक संग्रह में गिनना है। इसे प्राप्त करने के लिए, आप @count
संग्रह ऑपरेटर का उपयोग करें:
self.array = @[@5, @4, @3, @2, @1];
NSNumber *count = [self.array valueForKeyPath:@"@count"];
NSNumber *countAlt = [self valueForKeyPath:@"array.@count"];
// count == countAlt == 5
हालांकि यह पूरी तरह से बेमानी है (हम सिर्फ count
संपत्ति तक पहुंच सकते थे ), यह अवसर पर उपयोगी हो सकता है, हालांकि यह शायद ही कभी आवश्यक है। बहरहाल, कुछ संग्रह ऑपरेटरों कि और अधिक उपयोगी होते हैं अर्थात्, @max
, @min
, @sum
, @avg
और @unionOf
परिवार। यह नोट करना महत्वपूर्ण है कि इन ऑपरेटर भी सही ढंग से कार्य करने के लिए ऑपरेटर निम्नलिखित एक अलग कुंजी पथ की आवश्यकता है। यहां उनकी एक सूची और उनके साथ काम करने वाले डेटा का प्रकार है:
ऑपरेटर | डाटा प्रकार |
---|---|
@count | (कोई नहीं) |
@max | NSNumber , NSDate , int (और संबंधित), आदि। |
@min | NSNumber , NSDate , int (और संबंधित), आदि। |
@sum | NSNumber , int (और संबंधित), double (और संबंधित), आदि। |
@avg | NSNumber , int (और संबंधित), double (और संबंधित), आदि। |
@unionOfObjects | NSArray , NSSet , आदि। |
@distinctUnionOfObjects | NSArray , NSSet , आदि। |
@unionOfArrays | NSArray<NSArray*> |
@distinctUnionOfArrays | NSArray<NSArray*> |
@distinctUnionOfSets | NSSet<NSSet*> |
@max
और @min
संग्रह में वस्तुओं की संपत्ति के क्रमशः उच्चतम या निम्नतम मान लौटाएगा। उदाहरण के लिए, निम्नलिखित कोड देखें:
// “Point” class used in our collection
@interface Point : NSObject
@property NSInteger x, y;
+ (instancetype)pointWithX:(NSInteger)x y:(NSInteger)y;
@end
...
self.points = @[[Point pointWithX:0 y:0],
[Point pointWithX:1 y:-1],
[Point pointWithX:5 y:-6],
[Point pointWithX:3 y:0],
[Point pointWithX:8 y:-4],
];
NSNumber *maxX = [self valueForKeyPath:@"[email protected]"];
NSNumber *minX = [self valueForKeyPath:@"[email protected]"];
NSNumber *maxY = [self valueForKeyPath:@"[email protected]"];
NSNumber *minY = [self valueForKeyPath:@"[email protected]"];
NSArray<NSNumber*> *boundsOfAllPoints = @[maxX, minX, maxY, minY];
...
कोड और शुद्ध फाउंडेशन की सिर्फ 4 पंक्तियों में, की-वैल्यू कोडिंग संग्रह ऑपरेटरों की शक्ति के साथ हम एक आयत निकालने में सक्षम थे जो हमारे सरणी के सभी बिंदुओं को इनकैप्सुलेट करता है।
यह ध्यान रखना महत्वपूर्ण है कि इन तुलनाओं को वस्तुओं पर compare:
विधि को लागू करके बनाया जाता है, इसलिए यदि आप कभी भी इन ऑपरेटरों के साथ अपनी खुद की कक्षा बनाना चाहते हैं, तो आपको इस पद्धति को लागू करना होगा।
@sum
, जैसा कि आप शायद अनुमान लगा सकते हैं, एक संपत्ति के सभी मूल्यों को जोड़ सकते हैं।
@interface Expense : NSObject
@property NSNumber *price;
+ (instancetype)expenseWithPrice:(NSNumber *)price;
@end
...
self.expenses = @[[Expense expenseWithPrice:@1.50],
[Expense expenseWithPrice:@9.99],
[Expense expenseWithPrice:@2.78],
[Expense expenseWithPrice:@9.99],
[Expense expenseWithPrice:@24.95]
];
NSNumber *totalExpenses = [self valueForKeyPath:@"[email protected]"];
यहाँ, हमने सरणी में सभी खर्चों की कुल कीमत का पता लगाने के लिए @sum
का उपयोग किया। यदि हम इसके बजाय प्रत्येक कीमत के लिए भुगतान की जाने वाली औसत कीमत का पता लगाना चाहते हैं, तो हम @avg
उपयोग कर सकते हैं:
NSNumber *averagePrice = [self valueForKeyPath:@"[email protected]"];
अंत में, @unionOf
परिवार है। इस परिवार में पांच अलग-अलग ऑपरेटर हैं, लेकिन वे सभी एक ही काम करते हैं, जिनमें से प्रत्येक के बीच केवल छोटे अंतर हैं। सबसे पहले, वहाँ @unionOfObjects
जो एक सरणी में वस्तुओं के गुणों की एक सरणी लौटाएगा:
// See "expenses" array above
NSArray<NSNumber*> *allPrices = [self valueForKeyPath:
@"[email protected]"];
// Equal to @[ @1.50, @9.99, @2.78, @9.99, @24.95 ]
@distinctUnionOfObjects
कार्यों के रूप में ही @unionOfObjects
, लेकिन यह डुप्लिकेट निकालता है:
NSArray<NSNumber*> *differentPrices = [self valueForKeyPath:
@"[email protected]"];
// Equal to @[ @1.50, @9.99, @2.78, @24.95 ]
और अंत में, @unionOf
परिवार में अंतिम 3 संचालक एक कदम गहराई तक जाएंगे और एक संपत्ति के लिए पाए गए मानों की एक सरणी @unionOf
, जो @unionOf
-नेस्टेड ऐरे के अंदर निहित हैं:
NSArray<NSArray<Expense*,Expense*>*> *arrayOfArrays =
@[
@[ [Expense expenseWithPrice:@19.99],
[Expense expenseWithPrice:@14.95],
[Expense expenseWithPrice:@4.50],
[Expense expenseWithPrice:@19.99]
],
@[ [Expense expenseWithPrice:@3.75],
[Expense expenseWithPrice:@14.95]
]
];
// @unionOfArrays
NSArray<NSNumber*> allPrices = [arrayOfArrays valueForKeyPath:
@"@unionOfArrays.price"];
// Equal to @[ @19.99, @14.95, @4.50, @19.99, @3.75, @14.95 ];
// @distinctUnionOfArrays
NSArray<NSNumber*> allPrices = [arrayOfArrays valueForKeyPath:
@"@distinctUnionOfArrays.price"];
// Equal to @[ @19.99, @14.95, @4.50, @3.75 ];
इस उदाहरण से गायब होने वाला @distinctUnionOfSets
, हालाँकि यह ठीक @distinctUnionOfArrays
के समान है, लेकिन इसके साथ काम करता है और NSSet
लौटाता है (कोई distinct
संस्करण नहीं है क्योंकि एक सेट में, प्रत्येक वस्तु को वैसे भी अलग होना चाहिए)।
और बस! यदि सही ढंग से उपयोग किया जाता है तो संग्रह ऑपरेटर वास्तव में शक्तिशाली हो सकते हैं, और अनावश्यक रूप से सामान के माध्यम से लूप से बचने में मदद कर सकते हैं।
एक अंतिम नोट: आप NSNumber
s (अतिरिक्त प्रॉपर्टी एक्सेस के बिना) के सरणियों पर मानक संग्रह ऑपरेटरों का भी उपयोग कर सकते हैं। ऐसा करने के लिए, आप self
-छद्म संपत्ति का उपयोग करते हैं जो केवल वस्तु लौटाता है:
NSArray<NSNumber*> *numbers = @[@0, @1, @5, @27, @1337, @2048];
NSNumber *largest = [numbers valueForKeyPath:@"@max.self"];
NSNumber *smallest = [numbers valueForKeyPath:@"@min.self"];
NSNumber *total = [numbers valueForKeyPath:@"@sum.self"];
NSNumber *average = [numbers valueForKeyPath:@"@avg.self"];