Two small Core Foundation tips

Core Foundation is a straight C, yet object-orientated API layer of OS X. Here’s a couple of small tips:

1. Much of the source for Core Foundation is freely available, so if you’re wondering whether a CFArray will retain its items on creation (for example), wonder no more (http://opensource.apple.com/source/CF/).

2. The CFArrayCreate function takes a pointer to a record that contains a series of callback functions. If the array will be an array of other Core Foundation types, the docs say you should pass a pointer to kCFTypeArrayCallbacks. Do this in Delphi however, and the function will hang, or at least, it does for me. To be honest, I don’t really understand why, but the workaround is to declare a local variable typed to CFArrayCallbacks, which you can then assign kCFTypeArrayCallbacks to, after which the local can be referenced rather than kCFTypeArrayCallbacks directly. Here’s an example:

 
program ArraysAndNumFormatters;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Macapi.CoreFoundation;

function CFArrayCreateOfDouble(const Nums: array of Double): CFArrayRef;
var
  Callbacks: CFArrayCallBacks;
  CFNums: array of CFNumberRef;
  I: Integer;
begin
  SetLength(CFNums, Length(Nums));
  for I := 0 to High(Nums) do
    CFNums[I] := CFNumberCreate(nil, kCFNumberDoubleType, @Nums[I]);
  Callbacks := kCFTypeArrayCallBacks;
  Result := CFArrayCreate(nil, CFNums, Length(CFNums), @Callbacks);
  for I := 0 to High(Nums) do
    CFRelease(CFNums[I]);
end;

var
  Formatter: CFNumberFormatterRef;
  Locale: CFLocaleRef;
  NumArray: CFArrayRef;
  Num: CFNumberRef;
  I: Integer;
  Range: CFRange;
  CFStr: CFStringRef;
  DStr: string;
begin
  Locale := CFLocaleCopyCurrent;
  Formatter := CFNumberFormatterCreate(nil, Locale, kCFNumberFormatterPercentStyle);
  NumArray := CFArrayCreateOfDouble([0.11, 0.22, 0.33]);
  try
    for I := 0 to CFArrayGetCount(NumArray) - 1 do
    begin
      Num := CFArrayGetValueAtIndex(NumArray, I);
      CFStr := CFNumberFormatterCreateStringWithNumber(nil, Formatter, Num);
      try
        Range.location := 0;
        Range.length := CFStringGetLength(CFStr);
        SetLength(DStr, Range.length);
        CFStringGetCharacters(CFStr, Range, PChar(DStr));
        WriteLn(DStr);
      finally
        CFRelease(CFStr);
      end;
    end;
  finally
    CFRelease(NumArray);
    CFRelease(Formatter);
    CFRelease(Locale);
  end;
  WriteLn('Got to the end without crashing. Marvellous.');
end.

If the manual reference counting and objects-for-objects-sake style looks tedious, that’s because it is! On the other hand, the CF API is nice and clean if you can stand the verbosity…

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s