On 24/04/2009, at 9:56 , Wade Tregaskis wrote:

Something I've been using as of late to make CF a little more bearable is the cleanup attribute offered by gcc, e.g.:

static inline void _autoreleaseCFArray(CFArrayRef *array) {
        if (NULL != *array) {
                CFRelease(*array);
        }
}

#define CFAutoreleasedArrayRef __attribute__((cleanup(_autoreleaseCFArray))) CFArrayRef

Unfortunately there's an apparent bug in gcc that requires you to have exact type matches, so you can't make e.g. a generic CFTypeRef variant (unless your variables really are declared as CFTypeRefs). But still, if you're using a particular set of objects a lot, it can save you so much work.


I've used a CFContainer class with good results in my C++ code for Keyboard Maestro. Because of the magic of C++ the container is almost indistinguishable from a raw CF pointer - it takes up the same amount of space and you can pass it to routines requiring a CF pointer as normal.

The code follows, but an example usage might be:

CFContainer<CFStringRef> username = CopyViewText( kKMRegisterWindowUsernameID ); CFContainer<CFStringRef> serial = CopyViewText( kKMRegisterWindowSerialID );
if ( !RegisterUsernameSerial( username, serial ) ) {
        return;
}

Where RegisterUsernameSerial takes CFStringRef parameters.

C++ magic ensures the items are released when they go out of scope.

Using the typedef:

typedef CFContainer<CFStringRef> CFCS;

and more C++ magic, you can even do things like:

if ( !RegisterUsernameSerial( CFCS( CopyUsername() ), CFCS( CopySerial() ) ) ) {
        return;
}

The copied CFStringRefs are stored in the temporary container until the statement is finished and then released.

You can also do things like

CFContainer<CFStringRef> username = CopyViewText( kKMRegisterWindowUsernameID ); username = CFStringCreateWithFormat( kCFAllocatorDefault, NULL, CFSTR("Thus username is %@"), CFStringRef (username) );

And the original username will be released and a new one stored for later release.

Its not as clean as Cocoa's method, but on the other hand its more efficient than autorelease.

Code follows.

Enjoy,
   Peter.


template<class T>
class CFContainer
{
private:
        T mRef;

public:
        CFContainer() { mRef = NULL; };
        CFContainer( const T& ref ) { mRef = ref; };
        CFContainer( const CFContainer<T>& ref );
        ~CFContainer() { if ( mRef ) CFRelease( mRef ); };
        
        const T& Get() const { return mRef; };

        T Retain() const { CFRetain( mRef ); return mRef; };

        operator T() const { return mRef; };
        T operator->() const { return mRef; };
        
        CFContainer<T>& operator= ( const T& ref );
        CFContainer<T>& operator= ( const CFContainer<T>& c );
        
        bool operator! () { return mRef == NULL; };
        bool Defined() { return mRef != NULL; };
};


template<class T>
inline CFContainer<T>::CFContainer( const CFContainer<T>& ref )
{
        mRef = ref;
        if ( mRef ) {
                CFRetain( mRef );
        }
}


template<class T>
CFContainer<T>&
CFContainer<T>::operator=( const T& ref )
{
        if ( mRef ) {
                CFRelease( mRef );
        }
        mRef = ref;
        return *this;
}

template<class T>
CFContainer<T>&
CFContainer<T>::operator=( const CFContainer<T>& c )
{
        if ( &c != this ) {
                if ( mRef ) {
                        CFRelease( mRef );
                }
                mRef = c;
                if ( mRef ) {
                        CFRetain( mRef );
                }
        }
        return *this;
}

// Specific case to enable functionality like: CallFunc( CFCS( arg- >CopyName() ) );
typedef CFContainer<CFStringRef> CFCS;

// Stop people accidently releasing CFContainers cast to the underlying ref

extern void CFRelease( CFContainer<SafeCFTypeRef> ref );
extern void CFRelease( CFContainer<CFArrayRef> ref );
extern void CFRelease( CFContainer<CFBagRef> ref );
extern void CFRelease( CFContainer<CFBooleanRef> ref );
extern void CFRelease( CFContainer<CFDataRef> ref );
extern void CFRelease( CFContainer<CFDictionaryRef> ref );
extern void CFRelease( CFContainer<CFNumberRef> ref );
extern void CFRelease( CFContainer<CFSetRef> ref );
extern void CFRelease( CFContainer<CFStringRef> ref );
extern void CFRelease( CFContainer<CFURLRef> ref );
extern void CFRelease( CFContainer<CFUUIDRef> ref );
extern void CFRelease( CFContainer<CFMutableArrayRef> ref );
extern void CFRelease( CFContainer<CFMutableBagRef> ref );
extern void CFRelease( CFContainer<CFMutableDataRef> ref );
extern void CFRelease( CFContainer<CFMutableDictionaryRef> ref );
extern void CFRelease( CFContainer<CFMutableSetRef> ref );
extern void CFRelease( CFContainer<CFMutableStringRef> ref );

--
     Run macros from your iPhone with Keyboard Maestro Control!
         or take a break with Derzle for your iPhone

Keyboard Maestro <http://www.keyboardmaestro.com/> Macros for your Mac
Aragom Space War <http://www.stairways.com/iphone/aragom> Don't get killed!
Derzle <http://www.stairways.com/iphone/derzle> Enjoy a relaxing puzzle.
<http://www.stairways.com/>           <http://download.stairways.com/>




_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to