[futurebasic] How to use CFStringCreateWIthFormat

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : June 2013 : Group Archive : Group : All Groups

From: Brian S <fblistserve@...>
Date: Tue, 18 Jun 2013 13:57:34 -0700
From time to time I receive programming questions from clients and other folks. This response details a basic CF function, so I thought others might benefit. The question asked about building strings ( i.e. concatenate ) using Core Foundation(CF) and the response focuses on CFStringCreateWithFormat(). The response references example code at FB_5_7_6_Examples/Text/Print Columnar Data/PrintColumnarWIthGrid2.bas and it would be helpful to open it while following along. If you don’t have that example handy, the line of code being examined is:  string = fn CFStringCreateWithFormat( _kCFAllocatorDefault, #0, @"%@ %d %d", @"Data# ", i+1, j+1 )

A versatile CF string creator is CFStringCreateWithFormat()( btw: most CF calls have a similar call in Cocoa. In this case NSString has a stringWithFormat: method ). It allows concatenation of strings(CF), numbers ( whether they be integers or floats/doubles ), objects ( i.e. other CFCreated... objects ) and creates one string containing all. Referring to the example code, look in the function DoPrinting and towards the bottom is a nested 'for/next' loop using CFStringCreateWithFormat(). Basically, CFStringCreateWithFormat() accepts one or more input variables ( as many as needed - the input is not fixed ) and creates a CFStringRef ( on the left side of the equals sign ). For the first two parameters, leave them as _kCFAllocatorDefault and #0. The next set of parameters are called string format specifiers and are used a lot in C ( printf, sprintf among many ) and Objective-C. See here for list of string format specifiers ( same list in Xcode docs too ). The format specifiers are written in a NSString constant. NSString constants are written as @"some constant" ( actually FB translates the NSString constant to a CFSTR macro constant but don’t worry about that now ). The next thing to know is format specifiers start with the percent symbol ( % ). It will always be percent symbol followed by another symbol. The combination is a format specifier. For example %@ means an object will be supplied, %d means a signed 32-bit integer will be supplied. The format specifiers are positional from left to right in the format string. So the first one on the left is applied to the first data parameter ( in the example %@ refers to the NSString @"Data# " ). Moving from left to right the %d refers to the 'i+1' and the last %d applies to 'j+1'. Even though the number of format specifiers supplied is unlimited, they must match in number and position with the data supplied. In our example there are three format specifiers followed by three data parameters. That could have been twenty ( or fifteen, or 2 or 87 ---whatever is needed ) specifiers and 20 data parameters. In this example the format specifiers have a space between them. The spaces will populate to the created string. If the target string didn’t need spaces between the data elements the format string could have been written @"%@%d%d" instead of @"%@ %d %d". Notice the string is released after being used ( CFRelease ). This is required to avoid leaks and other related undesirable behavior. 

Another thought for learning. There are some ConsoleWindow functions specifically aimed at CF strings that might be helpful for learning CF without having to build a GUI. Here is an example of ConsolePrintCFString:

'-----------
include "ConsoleWindow"   // bringing in ConsoleWindow code automatically provides an event loop, so no need to code one.

dim as CFStringRef   s
dim as short  a, b, c : a = 1 : b = 2 : c = 29

appearance window _FBConsoleWndNum,"Give Window Title", (5, 50)-(300, 300)  // optional if default size ok


s = fn CFStringCreateWithFormat( _kCFAllocatorDefault, #0, @"%@ %d %d %d", @"Numbers are: ", a, b, c )

fn ConsolePrintCFString( s )
CFRelease( s )
'-----------

Some other format specifiers not found on that link ( but can be found elsewhere ) but useful are:
/r    carriage return - useful if you want the string to begin on a new line
/n    new line
/t    tab

Note: these format specifiers do NOT begin with a percent sign. So a format string for two integers and a carriage return would look like:

@"%d%d/r"

N.B. when code is moved to CF such as pascal strings to CFStrings, adoption of other CF collectors is the easier path. For example, if CFStrings are being collected in an array, putting them in a CFArray is going to be much simpler than trying manage them in a standard FB array ( whether dynamic or otherwise ). So, for example"

someStandardArray( i ) = fn CreateCGImageFromxxxxx // some fn that returns a CGImageRef or other 'created' ref.

That function returns a CGImageRef which is an object( pointer ). someStandardArray as a CFArray would be easier to manage. It’s technically possible to stuff pointers in a standard array but you’ll lose the power of the CFArray functions which won’t work on a standard array. 


Cheers,
Brian S.