-
Notifications
You must be signed in to change notification settings - Fork 0
Object Life Cycle
Objects in Duck are allocated and initialized just like they are in Objective-C, but since the C syntax is clunkier, Duck code typically uses macros to make things easier to read.
#include <Duck/Duck.h>
void foo( void )
{
// The DKNew() macro allocates and initializes an object...
DKObjectRef object1 = DKNew( SomeClass() );
// ...which is really just another way of writing
DKObjectRef object2 = DKInit( DKAlloc( SomeClass() ) );
// Many objects provide initializers beyond DKInit()...
DKStringRef string1 = DKStringInitWithCString( DKAlloc( DKStringClass() ), "Look, Jane. See Spot." );
// ...and its customary to provide macros to make these prettier
DKStringRef string2 = DKNewStringWithCString( "Look Jane. See Spot." );
}
Reference counting works almost exactly like pre-ARC reference counting in Objective-C. You retain objects with DKRetain
, release them with DKRelease
and add them to the current autorelease pool with DKAutorelease
.
#include <Duck/Duck.h>
void foo( void )
{
// Allocate and intialize a new string -- the reference count starts at 1
DKStringRef string = DKNewStringWithCString( "See Spot run." );
// Retain the string -- the reference count is now 2
DKRetain( string );
// Release the string -- the reference count is again 1
DKRelease( string );
// Add the string to the autorelease pool -- the reference count remains 1
// until the autorelease pool is drained
DKAutorelease( string );
}
Similar to Apple's Objective-C conventions, functions and macros that begin with DKAlloc
, DKNew
or DKCopy
return an object that must be released by the caller. All other functions return objects that, unless retained by the caller, are valid only until the current autorelease pool is drained.
#include <Duck/Duck.h>
void foo( void )
{
// string1 has a reference count of 1 and must be released
DKStringRef string1 = DKNewStringWithCString( "Run, Spot! Run!" );
// string2 also has a reference count of 1, but must be retained if we
// want to keep it around for later use
DKStringRef string2 = DKStringWithCString( "Jane sees Spot run." );
}
The Duck library also provides zeroing weak references to help break retain cycles.
#include <Duck/Duck.h>
void foo( void )
{
// Allocate a new object -- the reference count is 1
DKStringRef string = DKNewStringWithCString( "Way to go, Jane." );
// Retain a weak reference to the object -- the reference count is still 1
DKWeakRef weakRef = DKRetainWeak( string );
// Resolve the weak reference -- the reference count increases to 2
DKStringRef strongRef = DKResolveWeak( weakRef );
// Release the strong reference when we're done with it -- the reference count is 1 again
DKRelease( strongRef );
// Release the original reference -- the object is deallocated
DKRelease( string );
// Future attempts to resolve the weak reference return NULL
DKStringRef thisIsNull = DKResolveWeak( weakRef );
// Finally, release the weak reference once we're done with it
DKRelease( weakRef );
}
In Objective-C the autorelease pool is typically managed by the run loop; the Duck runtime is a bit more manual. In most cases you should just periodically call DKDrainAutoreleasePool
to release everything currently marked for autorelease. You can also use DKPushAutoreleasePool
and DKPopAutoreleasePool
to modify the scope of the current autorelease pool.
#include <Duck/Duck.h>
int main( int argc, const char * argv[] )
{
DKRuntimeInit( 0 );
while( 1 )
{
DKPushAutoreleasePool();
// Do stuff here...
DKPopAutoreleasePool();
}
// Release any leftovers
DKDrainAutoreleasePool();
return 0;
}
Copyright (c) 2017 Derek W. Nylen