2013-03-07 7 views
5

मैं सिर्फ shadowPath संपत्ति के लिए एक CABasicAnimation को विन्यस्त किया गया था का उपयोग करने की कोशिश कर रहा है और यह मुझे उत्सुक बनाया:ब्रिज आवश्यक कलाकारों, असंगत चेतावनी जबकि CGPathRef

shadowAnimation.toValue = (id)newShadowPath.CGPath; 

[ध्यान दें: एक CABasicAnimation वस्तु और newShadowPath एक UIBezierPath है shadowAnimation है ऑब्जेक्ट]

यह काम करता है और एक्सकोड में कोई त्रुटि/चेतावनी दिखाई नहीं दे रही है। लेकिन अगर मैं लिखने कि इतने की तरह:

CGPathRef test = newShadowPath.CGPath; 
shadowAnimation.toValue = (id)test; 

यह संकलन नहीं होगा यह चेतावनी संदेश फेंकने:

Cast of C pointer type 'CGPathRef' (aka 'const struct CGPath *') to Objective-C pointer type 'id' requires a bridged cast 

तो यह मेरे टाइप करने के लिए की आवश्यकता है इसे पसंद:

shadowAnimation.toValue = (__bridge id)test; 

अब ऐसा क्यों है? मुझे प्रारंभिक उदाहरण में एक ही त्रुटि क्यों नहीं मिलती है जब मैं केवल (आईडी) newShadowPath.CGPath का उपयोग करता हूं; ? क्या __bridge जगह पर भी डालना सही होगा, चाहे एक्सकोड किसी भी समस्या का पता नहीं लगाए? या क्या मुझे याद आ रहा है कि यहां क्या अंतर है?

उत्तर

2

अंतर का कारण क्लैंग 3.1 में पेश किए गए नए (और थोड़ा जटिल) रूपांतरण नियमों में निहित है।

सबसे पहले, की सुविधा देता है यह उबाल नीचे:

@@interface Foo : NSObject 
+ (CGPathRef)bar; 
@end 

CGPathRef foo(); 

void test() 
{ 
    // works without bridged cast: 
    id a = (id)[Foo bar]; 

    // needs bridged cast 
    id b = (__bridge id)foo(); 
} 

तो जब संदेश हम brdge कलाकारों को छोड़ सकते हैं, जबकि एक सामान्य कार्य कॉल इसकी आवश्यकता का परिणाम कास्टिंग। यह अजीब लगता है।

अंतर की वजह कैसे एआरसी कार्य करता है और विधि के नाम की व्याख्या में निहित है और तथाकथित C retainable pointer types (कोर फाउंडेशन वस्तुओं) की गिनती को बनाए रखने के बारे में मान्यताओं में योगदान दिया।

एआरसी गाइड के section 3.3.2 में ("ज्ञात अर्थ विज्ञान के साथ अभिव्यक्ति की retainable वस्तु सूचक प्रकार के रूपांतरण") आप विसंगति के लिए कारण मिल जाएगा:

कोई व्यंजक में जाना जाता है unretained अगर यह सी बनाए रखने योग्य सूचक प्रकार का एक रैवल्यू है और यह [...] एक संदेश भेजता है [...]

और

डाली संकार्य में जाना जाता है unretained [...] रूपांतरण के रूप में एक __bridge डाली

व्यवहार किया जाता है एक ही अनुभाग बताता है क्यों यह नहीं हैं सी कार्यों पर लागू होता है और समान धारणाओं को बनाने के लिए क्लैंग को सक्षम करने के लिए उन्हें कैसे सजाया जा सकता है। इसलिए हम, सी समारोह कॉल के लिए पुल कलाकारों से छुटकारा पाने के ऊपर से एक उदाहरण संशोधित कर सकते हैं और साथ ही:

CGPathRef foo() __attribute__((cf_returns_not_retained)); 

अपने अंतिम प्रश्न का उत्तर देने: यह दोनों ही स्थानों पर पुल डाली उपयोग करने के लिए सुरक्षित है। यह भी सुनिश्चित करता है कि एआरसी सही __bridge कास्ट चुनता है (यह विधि के नाम के आधार पर __bridge_transfer कास्ट चुन सकता है। इस मामले में यह __bridge का उपयोग करेगा)।

+0

वाह, इसका विश्लेषण करने के लिए इस तरह के प्रयास में जाने के लिए धन्यवाद। मैंने इसे सही उत्तर के रूप में फिर से स्वीकार कर लिया क्योंकि यह इस महान लंबाई में जाता है कि यह स्पष्ट करने के लिए कि क्या हो रहा है। –

2

यह एआरसी के कारण होता है, और जादू जो असाइनमेंट होने पर करता है।

जब आप अस्थायी चर CGPathRef test बनाते हैं और इसे असाइन करते हैं, तो एआरसी देखता है कि आप कोरबैंक उदाहरण का उपयोग कर रहे हैं जो मानक मेमोरी प्रतिमानों का पालन नहीं करता है और इसे बनाए रखने या कुछ भी फैंसी नहीं करता है।

बाद में, जब आप इस गैर-प्रबंधित उदाहरण को id -typed संपत्ति को असाइन करने का प्रयास करते हैं, तो एलएलवीएम फ्रीक ठीक है, क्योंकि ऐसा लगता है कि उसे उस उदाहरण के लिए स्मृति का प्रबंधन नहीं करना था, लेकिन अब इसे शुरू करना चाहिए करने के लिए (जो __bridge कीवर्ड का इरादा है)।

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

+0

मुझे नहीं पता कि यह स्पष्टीकरण कुछ भी स्पष्ट कैसे करता है। 'Id a = (id) [UIBezierPath new] क्यों है; 'काम, अभी तक' id b = (__bridge id) CGPathCreateCopy (NULL);' पुल कास्ट की आवश्यकता है? –

+2

@ निकोलई रुहे 'UIBezierPath' एक एआरसी-प्रबंधित वर्ग है, जिसमें यह सी-पॉइंटर नहीं है, यह एक उद्देश्य-सी सूचक है। 'CGPathCreateCopy' एक सी स्ट्रक्चर पॉइंटर देता है, जो एआरसी ब्रिज किए जाने तक प्रबंधित नहीं करता है। –

+0

भ्रम के लिए खेद है: मेरा मतलब था 'आईडी ए = (आईडी) [UIBezierPath नया] .CGPath; '। तो दोनों मामलों के बीच का अंतर केवल इतना है कि 'ए' को ओबीजेसी संदेश का नतीजा मिलता है जबकि बी बी को सी फंक्शन का नतीजा मिलता है। मुझे नहीं पता कि एआरसी को इन मामलों को अलग-अलग क्यों संभालना चाहिए। –

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