11

पर एक ऑटोरेलेज्ड CGColor लौटाता है जो मैं एआरसी का उपयोग करने के लिए अपनी परियोजना को परिवर्तित करने की प्रक्रिया में हूं।एआरसी

@implementation NSColor (MyCategory) 

- (CGColorRef)CGColor 
{ 
    NSColor *colorRGB = [self colorUsingColorSpaceName:NSCalibratedRGBColorSpace]; 
    CGFloat components[4]; 
    [colorRGB getRed:&components[0] 
       green:&components[1] 
       blue:&components[2] 
       alpha:&components[3]]; 
    CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); 
    CGColorRef theColor = CGColorCreate(space, components); 
    CGColorSpaceRelease(space); 
    return (CGColorRef)[(id)theColor autorelease]; 
} 

@end 

एआरसी के साथ ऐसा करने का सही तरीका क्या है: मैं एक विधि है कि एक autoreleased CGColor प्रतिनिधित्व रिटर्न के साथ NSColor पर एक वर्ग है? मैं एक बनाए रखा CGColor वापस नहीं करना चाहता।

XCode में एआरसी कनवर्टर

return (CGColorRef)[(__bridge id)theColor autorelease]; 

लेकिन यह है कि निम्न त्रुटि संदेश में परिणाम उपयोग करने का सुझाव:

[rewriter] यह CGColorRef 'के लिए का परिणाम कास्ट करने के लिए सुरक्षित नहीं है 'autorelease' संदेश; एक __bridge डाली एक नष्ट वस्तु के लिए एक सूचक में हो सकता है और एक वस्तु

+2

आपके पास यहां एक बहुत अच्छी मेमोरी लीक है। CGColorCreate एक CGColor ऑब्जेक्ट बनाएगा जो हर बार जब आप इस विधि को कॉल करेंगे तो स्मृति में आयोजित किया जाएगा। मैं अत्यधिक कुछ ऐसा करने का सुझाव देता हूं: 'CGColorRef colorRef = CGColorCreate (colorSpaceRGB, घटक); यूआईसीओलर * retColor = [UIColor colorWithCGColor: colorRef]; CGColorRelease (colorRef); वापसी retColor; ' – jfeldman

+2

क्या आपने प्रश्न पढ़ा था? मुझे पता है कि यह लीक है, यह मेरी समस्या है। मैं एक सीजीकॉलर वापस करना चाहता था, न कि यूआईसीओलर (यह एक ओएस एक्स सवाल है जैसा कि आप एनएससीओलर के उल्लेख से बता सकते हैं)। वैसे भी, यह एक साल पहले आधा जवाब दिया गया है। – DrummerB

उत्तर

7

CGColor एक कोर फाउंडेशन वस्तु है रिसाव हो __bridge_retained। आपको इसके साथ autorelease का उपयोग करने का प्रयास नहीं करना चाहिए। इसके बजाय, आपको अपनी विधि copyCGColor का नाम बदलना चाहिए और एक बनाए रखा ऑब्जेक्ट वापस करना चाहिए।

ऑटो-रिलीजिंग एक उद्देश्य-सी अवधारणा है। यह कोर फाउंडेशन स्तर पर मौजूद नहीं है।

चूंकि CGColor किसी भी उद्देश्य-सी कक्षा में टोल-फ्री नहीं है, तो यह ऑटोोरलीज करने की कोशिश करने के लिए बहुत अजीब है (भले ही वह काम कर सके)।

अद्यतन कुछ साल बाद

अब CoreFoundation स्तर पर CFAutorelease() (मावेरिक्स और iOS 7 के बाद से उपलब्ध है) है।

+5

हालांकि यह अजीब हो सकता है, एनएससीओएलओआरएचएच-सीजीकॉलर का कहना है: "एक ऑटोरेलेज्ड CGColor देता है।" –

+0

ओएस एक्स 10.9 (और आईओएस 7) में उपलब्ध है, अब एक CFAutorelease() फ़ंक्शन है। – NSDestr0yer

+0

क्या आप एक उदाहरण प्रदान कर सकते हैं? मैंने अपनी संपत्ति में 'CF_RETURNS_RETAINED' जोड़ा, लेकिन स्थिर विश्लेषक अभी भी एक संभावित रिसाव के बारे में शिकायत करता है ... – NSAddict

0

मुझे लगता है कि आप इस मामले में __bridge_transfer का उपयोग करना चाहते हैं।

Docs

8

मूलतः यह कोई अच्छा तरीका एआरसी में निम्न कोड में परिवर्तित करने क्योंकि वहाँ है:

CGColorRef a = ...; 
id b = [(id)a autorelease]; 
CGColorRef c = (CGColorRef)b; 
// do stuff with c 

कनवर्टर -autorelease दूर करता है और कुछ डाले पाट लेता है, लेकिन यह अटक जाती है:

CGColorRef a = ...; 
id b = (__bridge_transfer id)a; 
CGColorRef c = (__bridge_SOMETHING CGColorRef)b; 
// do stuff with c. Except the compiler sees that b is no longer being used! 

लेकिन माइग्रेटर __bridge_SOMETHING के लिए क्या करना चाहिए?

  • यह __bridge उठाता है, तो b अब नहीं किया जाता है, ताकि संकलक कर सकते हैं तुरंत रिहाई यह। यह दुर्घटनाग्रस्त है।
  • यदि यह __bridge_retained चुनता है, तो स्वामित्व वापस को "सीएफ-भूमि" में स्थानांतरित कर दिया गया है, लेकिन मूल कोड मान लिया गया है कि ऑब्जेक्ट स्वामित्व वाले पूल के स्वामित्व में होगा। कोड अब लीक है।ऐसा करने के लिए एक विधि से एक autoreleased सीएफ प्रकार वापस जाने के लिए केवल अच्छा कारण -

समस्या यह है कि एआरसी -autorelease बुला मनाही लेकिन गारंटी नहीं है कि एक वस्तु autorelease पूल में जोड़ा जाता है एक प्रलेखित विधि नहीं है लेकिन UIKit वर्गों के बहुत CF-टाइप किया गुण होते हैं (और MKOverlayPathView एक परमाणुCGPathRef संपत्ति जो एक autoreleased मान लौटाना चाहिए है)।

इस एआरसी की मुश्किल बिट्स मैं वास्तव में चाहते हैं कि बेहतर प्रलेखित किया गया था से एक है।

कुछ हुप्स आप के माध्यम से जो सफलता की डिग्री बदलती के साथ काम कर सकते हैं कूद कर सकते हैं। बढ़ती ickiness के आदेश में:

  1. एआरसी के बिना संकलित एक फ़ाइल में एक CFAutorelease() समारोह (लक्ष्य सेटिंग में संकलक झंडे को -fno-objc-arc जोड़ने → बिल्ड के चरण → संकलित सूत्रों का कहना है) को परिभाषित करें। मैं इसे पाठक के लिए एक अभ्यास के रूप में छोड़ देता हूं। यह काम करता है क्योंकि एआरसी कोड को एमआरसी कोड के साथ अंतःक्रिया करने की आवश्यकता है। यह शायद सबसे साफ समाधान है। (यह एक टिप्पणी को आकर्षित करने के लिए बाध्य है कि यह सीएफ उपसर्ग का उपयोग नहीं करना चाहिए, लेकिन जब तक आपको कोई लिंक त्रुटि दिखाई नहीं दे रही है, सी प्रतीक नाम टकराव आम तौर पर सुरक्षित होते हैं क्योंकि "दो-स्तर के नामस्थान" की शुरुआत की जाती है 10.3 या उससे भी अधिक में।)

  2. विभिन्न हुप्स इसे -autorelease संदेश या समकक्ष भेजने के लिए। इन सभी के एक सा गन्दा क्योंकि वे एआरसी "बेवकूफ बनाना", पिछले एक जो id मान लिया गया है को छोड़कर पर भरोसा कर रहे हैं void* साथ ABI-संगत है। उन्होंने यह भी शायद ऊपर की तुलना में धीमी कर रहे हैं क्योंकि वे एक वर्ग/चयनकर्ता (objc_lookUpClass() और तेजी से या यहाँ तक कि दूर अनुकूलित हो सकता है, लेकिन मैं इस पर यकीन नहीं होता) को देखने के लिए की जरूरत है।

    return (__bridge CGColorRef)[(__bridge id)theColor performSelector:NSSelectorFromString(@"autorelease")] 
    
    [NSClassFromString(@"NSAutoreleasePool") addObject:(__bridge id)theColor] 
    return theColor; 
    
    return (__bridge CGColorRef)((id(*)(id,SEL))objc_msgSend)((__bridge id)theColor,NSSelectorFromString(@"autorelease")); 
    
    return ((void*(*)(void*,SEL))objc_msgSend)(theColor,NSSelectorFromString(@"autorelease")); 
    
  3. फोर्स यह एक __autoreleasing चर को बताए कि संकलक दूर अनुकूलित नहीं कर सकते द्वारा autorelease पूल में शामिल होना। मुझे यकीन है कि अगर यह गारंटी है नहीं कर रहा हूँ (विशेष रूप से, objc_autoreleaseReturnValue() और objc_retainAutoreleasedReturnValue() को कुछ इसी तरह संभव हो सकता है, लेकिन मुझे लगता है कि यह संभावना नहीं है, क्योंकि यह (NSError * __autoreleasing *)error की सामान्य स्थिति को धीमा होगा)।

    -(id)forceAutorelease:(id)o into:(id __autoreleasing*)p 
    { 
        *p = o; 
        return p; 
    } 
    
    -(CGColorRef)CGColor 
    { 
        ... 
        CGColorRef theColor = CGColorCreate(...); 
        CGColorSpaceRelease(space); 
        id __autoreleasing temp; 
        return (__bridge CGColorRef)[self forceAutorelease:(__bridge_transfer id)theColor into:&temp]; 
    } 
    

    (यह भी के लिए संकलक/क्रम को सहयोग करने और स्थिर प्रेषण/इनलाइनिंग का उपयोग जब तक प्रासंगिक तरीकों अधिरोहित कर रहे हैं संभव हो सकता है, लेकिन यह मुश्किल लगता है और नहीं अपनी खुद की महत्वपूर्ण ओवरहेड्स बिना।)

  4. __attribute__((NSObject)) के साथ एक typedef

    का प्रयोग करें। यह सबसे भ्रमित करने वाले दस्तावेज ARC spec के कुछ हिस्सों है, लेकिन इस की तरह कुछ करने के लिए काम लगता है:

    typedef CGColorRef MyCGColorRef __attribute__((NSObject)); 
    -(MyCGColorRef)CGColor 
    { 
        ... 
        return (__bridge MyCGColorRef)(__bridge_transfer id)theColor; 
    } 
    

    मुझे लगता है कि आप (एक के लिए एआरसी और एक अन्य को स्वामित्व हस्तांतरण कर काम करने के लिए इस के लिए दो पुलों की जरूरत है); यदि आप बस return theColor; मुझे संदेह है कि यह लीक हो गया है। दस्तावेज़ों के पढ़ने से, को केवल (__bridge_transfer MyCGColorRef) की आवश्यकता है क्योंकि यह एक गैर-एआरसी पॉइंटर (CGColorRef) से एक एआरसी पॉइंटर (MyCGColorRef) में परिवर्तित हो रहा है, लेकिन यह संकलक शिकायत करता है। हां, दस्तावेज़ __attribute__((NSObject)) टाइपपीफ का उपयोग करने के तरीके के बारे में कोई उदाहरण नहीं देते हैं।

    ध्यान दें कि आपको हेडर में रिटर्न प्रकार बदलने की आवश्यकता नहीं है। ऐसा करने से ऑटोरेलेज्ड रिटर्न वैल्यू ऑप्टिमाइज़ेशन सक्षम हो सकता है, लेकिन मुझे यकीन नहीं है कि कंपाइलर MyCGColorRef से CGColorRef में रूपांतरण को कैसे प्रबंधित करता है। ले श्वास

1

दरअसल, स्मृति प्रबंधन को में आप कर सकते हैं retain, release और autorelease किसी भी CoreFoundation वस्तु, क्योंकि वे सभी कर रहे हैं टोल फ्री पाट लिए कम से कम NSObject

चूंकि एआरसी मैन्युअल मेमोरी प्रबंधन का उपयोग करने से मना करता है, इसलिए हमें किसी भी तरह संकलक को संकेत देना चाहिए कि क्या करना है। एक तरीका है कि आपकी विधि - (CGColorRef)copyCGColor; नाम दें ताकि संकलक +1 रीटैन गिनती के साथ विधि रिटर्न ऑब्जेक्ट को जान सके।

लेकिन अगर तुम मुझे पसंद कर रहे हैं और सादे पसंद करते हैं "CGColor" इस तरह के तरीकों के लिए, तो आप सिर्फ __attribute__((cf_returns_retained)) विधि परिभाषा को संलग्न कर सकते हैं:

@interface NSColor (MyCategory) 

- (CGColorRef)CGColor __attribute__((cf_returns_retained)); 

@end 
4

ओएस के साथ शुरू एक्स 10.9 या iOS 7 तुम सिर्फ CFAutorelease() उपयोग कर सकते हैं (CFBase.h में घोषित)।