15

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

हालांकि, मेरे एपीआई के इस हिस्से के लिए, कॉलबैक और युक्त वस्तु का जीवन चक्र बाहरी रूप से बनाए रखा जाता है। मुझे पता है कि जब वस्तु को हटाया जाना चाहिए तो मैं चक्र को तोड़ सकता हूं।

मैं #pragma clang diagnostic ignored "-Warc-retain-cycles" के साथ प्रति फ़ाइल आधार पर बनाए रखने चक्र चेतावनी को बंद कर सकता हूं, लेकिन यह पूरी फ़ाइल के लिए चेतावनी को अक्षम करता है। मैं उस चेतावनी के आसपास #pragma clang diagnostic push और pop के साथ ब्लॉक को घेर सकता हूं, लेकिन यह ब्लॉक बदसूरत बनाता है।

मैं स्वयं को संदर्भित करने के बजाए स्वयं को इंगित करने के लिए एक __weak चर को संदर्भित करके दूर जाने की चेतावनी भी प्राप्त कर सकता हूं, लेकिन यह ब्लॉक को उपयोग करने के लिए बहुत कम सुखद बनाता है।

सबसे अच्छा समाधान मैं ले कर आए हैं इस मैक्रो कि ब्लॉक के चारों ओर नैदानिक ​​अक्षम करना करता है:

#define OBSERVE(OBJ, OBSERVEE, PATH, CODE) \ 
[(OBJ) observeObject:(OBSERVEE) forKeyPath:(PATH) withBlock:^(id obj, NSDictionary *change) { \ 
_Pragma("clang diagnostic push") \ 
_Pragma("clang diagnostic ignored \"-Warc-retain-cycles\"") \ 
do { CODE; } while(0); \ 
_Pragma("clang diagnostic pop") \ 
}]; 

काम करता है यही कारण है कि, लेकिन यह API उपयोगकर्ताओं के लिए बहुत खोज योग्य नहीं है, यह नेस्टेड की अनुमति नहीं है पर्यवेक्षक, और यह एक्सकोड के संपादक के साथ खराब तरीके से बातचीत करता है। चेतावनी को अक्षम या टालने का कोई बेहतर तरीका है?

+10

'स्वयं' के लिए '__weak' संदर्भ बनाना सचमुच कोड की एक पंक्ति लेता है। मुझे लगता है कि इस मामले में समस्या को ठीक करना लक्षणों को कम करने की कोशिश करने से बेहतर है। 'स्वयं' के बजाय 'कमजोर स्वयं' को संदर्भित करने के लिए ब्लॉक को कम सुखद बनाने का संदर्भ कैसे दिया जाता है? –

+3

यह दो तरीकों से कम सुखद है। श्रोताओं अक्सर बहुत कम होते हैं, कभी-कभी एक ही कथन। __weak घोषणा श्रोता के आकार को दोगुना करती है। इसका मतलब यह भी है कि आपको अनुमानित आत्म का उपयोग करने के बजाय संपत्ति पहुंच अर्हता प्राप्त करने की आवश्यकता है। मैं इस बात से सहमत हूं कि मेरा वर्तमान समाधान शायद __weak का उपयोग करने से भी बदतर है, लेकिन मैं इस प्रश्न के माध्यम से बेहतर एक प्राप्त करने की उम्मीद कर रहा था। –

+1

क्या आप "पूर्ण" तर्क स्वीकार करने के लिए अपने समापन ब्लॉक के प्रोटोटाइप को बदल सकते हैं? अब वह कोड जहां आप अपने ब्लॉक पास करते हैं, वही दिखाई देगा (एक अतिरिक्त तर्क स्वीकार करने के अलावा) और आप चेतावनियों को खत्म कर सकते हैं। (यानी आपके एपीआई ने आपके ब्लॉक पर ऑब्जेक्ट को अपने ब्लॉक में पास कर दिया है) – nielsbot

उत्तर

7

के साथ, वहाँ #pragma का उपयोग कर कोड के कुछ लाइनों के लिए चेतावनी निष्क्रिय करने के लिए एक आसान तरीका है शुरू करने के लिए:

#pragma clang diagnostic push 
#pragma clang diagnostic ignored "<#A warning to ignore#>" 
<#Code that issues a warning#> 
#pragma clang diagnostic pop 

लेकिन मैं इस विशेष मामले में इसका इस्तेमाल नहीं होता, क्योंकि यह समस्या का समाधान नहीं होगा , यह सिर्फ डेवलपर से छुपाएगा। मैं प्रस्तावित समाधान के साथ जाऊंगा कि मार्क प्रस्तावित है।

__weak typeof(self) weakSelf = self; // iOS ≥ 5 
__unsafe_unretained typeof(self) unsafeUnretainedSelf = self; // 5 > iOS ≥ 4 
__block typeof(self) blockSelf = self; // ARC disabled 
0

नया LLVM का पता लगाने में बेहतर है/इस तरह के iOS6 के साथ चक्र को बनाए रखने LLVM शिपिंग के लिए इंतजार या बनाने के साथ एलेक्स के तरीके से करना रोकने: एक कमजोर संदर्भ बनाने के लिए, आप ब्लॉक के निम्नलिखित के बाहर से एक कर सकते हैं एक कमजोर var।

चेतावनी को अक्षम करना हालांकि एक बुरा विचार है!

1

मुझे लगता है कि चेतावनी को अक्षम करना वर्तमान में एकमात्र सही तरीका है, क्योंकि यह कंपाइलर कहता है: इस बनाए रखने वाले चक्र की परवाह न करें, मुझे इसके बारे में पता है और मैं स्वयं पर्यवेक्षक का निपटान करूंगा। एक कमजोर संदर्भ पेश करना एक महंगा समाधान है क्योंकि यह रनटाइम सीपीयू और मेमोरी ओवरहेड के साथ आता है।

0

मैं निम्नलिखित मैक्रो, जो मुझे लगता है कि लिखा था,

#define CLANG_IGNORE_HELPER0(x) #x 
#define CLANG_IGNORE_HELPER1(x) CLANG_IGNORE_HELPER0(clang diagnostic ignored x) 
#define CLANG_IGNORE_HELPER2(y) CLANG_IGNORE_HELPER1(#y) 

#define CLANG_POP _Pragma("clang diagnostic pop") 
#define CLANG_IGNORE(x)\ 
    _Pragma("clang diagnostic push");\ 
    _Pragma(CLANG_IGNORE_HELPER2(x)) 

यह आप (Xcode बिना आप haranguing) जैसे मजेदार बातें की सभी प्रकार करने के लिए, की अनुमति देता है बहुत चालाक है ... ..

CLANG_IGNORE(-Warc-retain-cycles) 
[object performBlock:^(id obj){ [obj referToSelfWithoutWarning:self]; }]; 
CLANG_POP 

आप किसी चेतावनी ध्वज में डाल सकते हैं और क्लैंग आपकी इच्छाओं पर ध्यान देगी ...

CLANG_IGNORE(-Warc-performSelector-leaks); 
return [self performSelector:someIllBegotSelector withObject:arcFauxPas]; 
CLANG_POP 

फिर, चेतावनी आमतौर पर वहाँ एक कारण के लिए कर रहे हैं। पार्टी poppers।

0

एक कमजोर संदर्भ बनाने की कठोरता की समस्या को हल करने के लिए, मैंने इसे एक मैक्रो में रखा। यह एक ही नाम के साथ लेकिन एक उपसर्ग के साथ एक नया वर बनाने के लिए पूर्वप्रक्रमक का उपयोग करता है ('w', इस मामले में, मैं बचा 'कमजोर' क्योंकि कि overkill हो सकता है और पूंजीकरण के नियमों के साथ गड़बड़ अधिक होगा):

#define WEAK_VAR(NAME) __unsafe_unretained typeof(NAME) w##NAME = NAME 

... 
WEAK_VAR(self); 
self.block = ^{ 
    [wself doStuff]; 
}; 

यदि, ओटो, एक कमजोर संदर्भ वांछनीय नहीं है, इसका उपयोग न करें! मुझे ऑब्जेक्ट को पैरामीटर के रूप में पास करने के nielsbot समाधान पसंद है (जब संभव हो, बिल्कुल)।

संबंधित मुद्दे