OS X 10.6 और iOS 4.0 में, Apple ने
ब्लॉकों के लिए समर्थन की घोषणा की, जो अनिवार्य रूप से
बंद हो रहे हैं। आईओएस के लिए विकास के संदर्भ में ब्लॉकों के बारे में आगे, उद्देश्य-सी (यानी, बिना
जीसी के काम)।
IOS वर्जन का उपयोग करने के लिए। <4.0, आप
ESBlockRuntime या
PLBlocks लागू कर सकते हैं।
सिद्धांत के बारे में संक्षेप में
ब्लॉक उदाहरण, ब्लॉक प्रकार, और ब्लॉक शाब्दिक को स्वयं ^ ऑपरेटर का उपयोग करके इंगित किया जाता है, उदाहरण के लिए:
typedef int (^MyBlock)( int );
int multiplier = 7;
MyBlock myBlock = ^( int num) {
return num * multiplier;
};
* This source code was highlighted with Source Code Highlighter .
या
int multiplier = 7;
int (^myBlock)( int ) = ^( int num) {
return num * multiplier;
};
* This source code was highlighted with Source Code Highlighter .
एक ब्लॉक के लिए एक कॉल एक नियमित कार्य के लिए एक कॉल के समान है। उदाहरण के लिए, इस तरह:
myBlock( 3 )
* This source code was highlighted with Source Code Highlighter .
ब्लॉकों की मुख्य विशेषता उनके संदर्भ को संग्रहीत करने की उनकी क्षमता है जिसमें वे बनाए गए थे। उपरोक्त उदाहरण में, "myBlock" हमेशा संख्या को 7. से गुणा करेगा। यह सब कैसे काम करता है?
ब्लॉक संदर्भ चर के प्रकार
1. आदिम प्रकार सी और संरचनाएं, ब्लॉकों को स्थिरांक के रूप में संग्रहीत किया जाता है। एक उदाहरण:
int multiplier = 7;
int (^myBlock)( int ) = ^( int num) {
return num * multiplier;
};
multiplier = 8;
NSLog( @"%d" , myBlock( 3 ) );
* This source code was highlighted with Source Code Highlighter .
प्रिंट्स - 21, 24 नहीं।
2. __block कीवर्ड के साथ परिभाषित चर परस्पर भिन्न होते हैं। यह इस तरह के वैरिएबल के मान को ढेर में कॉपी करके काम करता है और प्रत्येक ब्लॉक इस वैरिएबल के लिंक को स्टोर करता है। एक उदाहरण:
__block int multiplier = 7;
int (^myBlock)( int ) = ^( int num) {
return num * multiplier;
};
multiplier = 8;
NSLog( @"%d" , myBlock( 3 ) );
* This source code was highlighted with Source Code Highlighter .
प्रिंट्स - 24, 21 नहीं।
3. चर - संदर्भ गिनती (आईडी, NSObject) के साथ वस्तुओं को इंगित करता है। ब्लॉक के ढेर में नकल होने पर उनके लिए रिटेन बुलाया जाता है। एक उदाहरण:
NSDate* date = [ [ NSDate alloc ] init ];
void (^printDate)() = ^() {
NSLog( @"date: %@" , date );
};
//
printDate = [ [ printDate copy ] autorelease ];
[ date release ];
printDate();
* This source code was highlighted with Source Code Highlighter .
यहां मैं इस तथ्य पर आपका ध्यान आकर्षित करना चाहता हूं कि डेट ऑब्जेक्ट का रखरखाव ठीक उसी समय होता है जब ब्लॉक को ढेर में कॉपी किया जाता है, न कि इसके निर्माण के दौरान। उदाहरण के लिए, यह कोड "EXC_BAD_ACCESS" से गिर जाएगा
NSDate* date = [ [ NSDate alloc ] init ];
void (^printDate)() = ^() {
NSLog( @"date: %@" , date );
};
[ date release ];
//
printDate = [ [ printDate copy ] autorelease ];
printDate();
* This source code was highlighted with Source Code Highlighter .
4. चर - संदर्भ गिनती के साथ वस्तुओं के लिए संकेत (आईडी, NSObject) __block कीवर्ड के साथ घोषित किया गया। एक ब्लॉक को ढेर में कॉपी करते समय उनके लिए रिटेन
नहीं बुलाया जाता है । एक उदाहरण:
__block NSDate* date = [ [ NSDate alloc ] init ];
void (^printDate)() = ^() {
// date
NSLog( @"date: %@" , date );
};
// , date retain
printDate = [ [ printDate copy ] autorelease ];
[ date release ];
printDate();
* This source code was highlighted with Source Code Highlighter .
यह आमतौर पर परिपत्र संदर्भों से बचने के लिए उपयोग किया जाता है। एक उदाहरण:
@ interface SomeClass : NSObject
//
@property ( nonatomic, copy ) SimpleBlock block;
@end
@implementation SomeClass
@synthesize block = _block;
-( void )dealloc
{
[ _block release ];
[ super dealloc ];
}
-( void )methodB
{
}
-( void )methodA
{
__block SomeClass* self_ = self;
// ( ) - ,
self.block = ^()
{
// retain self_
[ self_ methodB ];
};
}
@end
* This source code was highlighted with Source Code Highlighter .
ब्लॉक NSObject वर्ग के उदाहरण हैं (इन वस्तुओं के विशिष्ट वर्ग परिभाषित नहीं किए गए हैं), इसलिए हम NSObject वर्ग के तरीकों का उपयोग करने के लिए मजबूर हो सकते हैं - ब्लॉक के लिए कॉपी, रिटेन, रिलीज और ऑटोरेलिज। लेकिन हमें इसकी आवश्यकता क्यों है?
ब्लॉक और मेमोरी प्रबंधन
डिफ़ॉल्ट रूप से, ब्लॉक इंस्टेंस ढेर पर नहीं बनाए जाते हैं, जैसा कि कोई मान सकता है, लेकिन स्टैक पर। इसलिए, यदि आवश्यक हो, तो ब्लॉक को एक आस्थगित कॉल करें, आपको पहले इसे ढेर में कॉपी करना होगा।
मान लीजिए कि "PerformAfterDelay:" विधि के साथ NSObject क्लास का विस्तार है, जो दिए गए ब्लॉक को देरी से निष्पादित करता है।
@implementation NSObject (BlocksExtensions)
-( void )callSelfBlock
{
void * self_ = self;
ESSimpleBlock block_ = (ESSimpleBlock)self_;
block_();
}
-( void )performAfterDelay:( NSTimeInterval )delay_
{
[ self performSelector: @selector( callSelfBlock ) withObject: nil afterDelay: delay_ ];
}
@end
* This source code was highlighted with Source Code Highlighter .
और, वास्तव में, कॉल:
NSDate* date = [ NSDate date ];
void (^printDate)() = ^() {
NSLog( @"date: %@" , date );
};
[ printDate performAfterDelay: 0.3 ];
* This source code was highlighted with Source Code Highlighter .
ऐसा कोड हमारे आवेदन को "डंप" करेगा, क्योंकि कॉल के समय तक स्टैक ब्लॉक नष्ट हो जाएगा, और हम उस स्थान पर यादृच्छिक मेमोरी में बदल जाएंगे जहां ब्लॉक को बुलाया गया था। हालांकि यह कोड है:
void (^printDate)() = ^() {
NSLog( @"date: %@" , [ NSDate date ] );
};
[ printDate performAfterDelay: 0.3 ];
* This source code was highlighted with Source Code Highlighter .
बढ़िया काम करेगा। क्या कारण है? कृपया ध्यान दें कि अंतिम ब्लॉक बाहरी चर का संदर्भ नहीं देता है, इसलिए इसकी एक प्रति बनाने की कोई आवश्यकता नहीं है। इस मामले में, कंपाइलर तथाकथित ग्लोबल ब्लॉक बनाता है। कार्यक्रम में इस तरह के ब्लॉक का केवल एक उदाहरण है, जिसका जीवनकाल आवेदन के जीवनकाल तक सीमित है। इस प्रकार, ग्लोबलब्लॉक को एक एकल वस्तु के रूप में माना जा सकता है।
ब्लॉक चर के प्रकार
और इसलिए, संक्षेप में। तीन प्रकार के ब्लॉक हैं: ग्लोबल (स्टेटलेस), लोकल या स्टैक्ड, और हीप पर ब्लॉक (मॉलोकब्लॉक)। इसलिए, ग्लोबल ब्लॉक की कॉपी, रिटेन, रिलीज और ऑटोरेलिज के तरीके कुछ नहीं करते हैं। स्टैक ब्लॉक के लिए रिटेन विधि भी कुछ नहीं करती है। मलोक ब्लॉक के लिए, कॉपी विधि बदले में NSObject के लिए बरकरार रहती है।
और निश्चित रूप से, कॉपी विधि के अलावा पिछले उदाहरण का संशोधित संस्करण:
@implementation NSObject (BlocksExtensions)
-( void )callSelfBlock
{
void * self_ = self;
ESSimpleBlock block_ = (ESSimpleBlock)self_;
block_();
}
-( void )performAfterDelay:( NSTimeInterval )delay_
{
// , - afterDelay:
self = [ [ self copy ] autorelease ];
[ self performSelector: @selector( callSelfBlock ) withObject: nil afterDelay: delay_ ];
}
@end
* This source code was highlighted with Source Code Highlighter .
निरंतरता:
"ब्लॉक पर और उद्देश्य-सी भाग 2 में उनका उपयोग"