Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
CFPreferences.c
// File: CFPreferences.c |
// Abstract: Sample code to show one way to use the CFPreferences API's to access user preferences. |
// Version: 1.1 |
// |
// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
// Inc. ("Apple") in consideration of your agreement to the following |
// terms, and your use, installation, modification or redistribution of |
// this Apple software constitutes acceptance of these terms. If you do |
// not agree with these terms, please do not use, install, modify or |
// redistribute this Apple software. |
// |
// In consideration of your agreement to abide by the following terms, and |
// subject to these terms, Apple grants you a personal, non-exclusive |
// license, under Apple's copyrights in this original Apple software (the |
// "Apple Software"), to use, reproduce, modify and redistribute the Apple |
// Software, with or without modifications, in source and/or binary forms; |
// provided that if you redistribute the Apple Software in its entirety and |
// without modifications, you must retain this notice and the following |
// text and disclaimers in all such redistributions of the Apple Software. |
// Neither the name, trademarks, service marks or logos of Apple Inc. may |
// be used to endorse or promote products derived from the Apple Software |
// without specific prior written permission from Apple. Except as |
// expressly stated in this notice, no other rights or licenses, express or |
// implied, are granted by Apple herein, including but not limited to any |
// patent rights that may be infringed by your derivative works or by other |
// works in which the Apple Software may be incorporated. |
// |
// The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
// |
// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
// POSSIBILITY OF SUCH DAMAGE. |
// |
// Copyright (C) 2010 Apple Inc. All Rights Reserved. |
// |
// **************************************************** |
#pragma mark - |
#pragma mark * complation directives * |
// ---------------------------------------------------- |
#define kMaxNumHighScores 10 |
// **************************************************** |
#pragma mark - |
#pragma mark * includes & imports * |
// ---------------------------------------------------- |
#include <Carbon/Carbon.h> |
#include <CoreFoundation/CFPreferences.h> |
#include <stdio.h> |
// **************************************************** |
#pragma mark - |
#pragma mark * typedef's, struct's, enums, defines, etc. * |
// ---------------------------------------------------- |
#define kHighScoresKeyCFStr CFSTR( "High Scores" ) |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function prototypes * |
// ---------------------------------------------------- |
static char * Copy_CFStringRefToCString( CFStringRef inCFStringRef ); |
static void HighScores_Dump( void ); |
static __inline__ int random_UInt32_between( UInt32 inStart, UInt32 inStop ); |
static Boolean HighScores_Update( const char * inPlayer, SInt32 inScore ); |
static Boolean HighScores_Reset( void ); |
// **************************************************** |
#pragma mark - |
#pragma mark * exported globals * |
// ---------------------------------------------------- |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) globals * |
// ---------------------------------------------------- |
// **************************************************** |
#pragma mark - |
#pragma mark * exported function implementations * |
// ---------------------------------------------------- |
// ***************************************************** |
// |
// Routine: main ( ) |
// |
// Purpose: Generates 100 random scores and attempts to add them to the high score preference |
// |
// Inputs: none |
// |
// Returns: int - error code ( 0 == no error ) |
// |
int main( void ) |
{ |
SInt32 idx; |
UInt32 score; |
Boolean again = TRUE; |
#if TRUE // enable to extract CFBundleGetInfoString from bundle |
{ |
CFBundleRef bundleRef = CFBundleGetMainBundle( ); |
if ( bundleRef ) { |
CFTypeRef tCFTypeRef = CFBundleGetValueForInfoDictionaryKey( bundleRef, CFSTR( "CFBundleGetInfoString" ) ); |
if ( tCFTypeRef ) { |
char * versionStrPtr = Copy_CFStringRefToCString( tCFTypeRef ); |
printf( "\nWelcome to %s!\n", versionStrPtr ); |
DisposePtr( versionStrPtr ); |
CFRelease( tCFTypeRef ); |
} |
} |
} |
#endif |
printf("Before: "); |
HighScores_Dump( ); |
while ( again ) { |
// generate one hundred random scores... |
for ( idx = 0; idx < 100; idx++ ) { |
Str255 playerString; |
sprintf( ( Ptr ) playerString, "Player #%.3ld", idx ); |
score = random_UInt32_between( 0, 100000 ); |
// update the high scores... |
// ... if our socre is a high score... |
if ( HighScores_Update( ( Ptr ) playerString, score ) ) { |
again = FALSE; // terminate outer loop |
} |
} |
// if we didn't generate any new high scores... |
if ( again ) { |
// ... reset the high scores list (pref) |
printf( "Resetting the high scores list...\n" ); |
again = HighScores_Reset( ); |
} |
} |
printf("After: "); |
HighScores_Dump( ); |
return 0; |
} // main |
// **************************************************** |
#pragma mark - |
#pragma mark * local ( static ) function implementations * |
// ---------------------------------------------------- |
// ***************************************************** |
// |
// Routine: Copy_CFStringRefToCString ( inCFStringRef ) |
// |
// Purpose: return a C string from a CFString |
// |
// Note: If not NULL the result has to be DisposePtr'ed. |
// |
// Inputs: inCFStringRef - the CFString to extract the C string from |
// |
// Returns: char * - pointer to C string buffer or NULL on error |
// |
static char * Copy_CFStringRefToCString( CFStringRef inCFStringRef ) |
{ |
char * result = NULL; |
if ( inCFStringRef ) { |
CFIndex length = sizeof( UniChar ) * CFStringGetLength( inCFStringRef ) + 1; |
result = ( char * ) NewPtrClear( length ); |
if ( result ) { |
if ( !CFStringGetCString( inCFStringRef, result, length, kCFStringEncodingASCII ) ) { |
if ( !CFStringGetCString( inCFStringRef, result, length, kCFStringEncodingUTF8 ) ) { |
DisposePtr( result ); |
result = NULL; |
} |
} |
} |
} |
return result; |
} // Copy_CFStringRefToCString |
// ***************************************************** |
// |
// Routine: random_UInt32_between ( inStart, inStop ) |
// |
// Purpose: generate a random UInt32 between start & stop ( inclusive ) |
// |
// Inputs: inStart - UInt32 bottom of range |
// inStop - UInt32 top of range |
// |
// Returns: UInt32 - the random number |
// |
static __inline__ int random_UInt32_between( UInt32 inStart, UInt32 inStop ) |
{ |
UInt32 range = ( ( inStart < inStop ) ? ( inStop - inStart ) : ( inStart - inStop ) ) + 1; |
static UInt32 seed = 0; |
if ( !seed ) { // if the seed is zero... |
seed = CFAbsoluteTimeGetCurrent( ); |
srandom( seed ); |
} |
seed = range * ( ( float ) random( ) / ( float ) RAND_MAX ); |
return ( ( inStart < inStop ) ? inStart : inStop ) + seed; |
} // random_UInt32_between |
// ***************************************************** |
// |
// Routine: HighScores_Dump ( ) |
// |
// Purpose: dump the high scores (duh!) |
// |
// Inputs: none |
// |
// Returns: none |
// |
static void HighScores_Dump( void ) |
{ |
// get the current high scores |
CFArrayRef prefCFArrayRef = CFPreferencesCopyAppValue( kHighScoresKeyCFStr, kCFPreferencesCurrentApplication ); |
if ( !prefCFArrayRef ) |
return; |
// how many did we get? |
CFIndex countHighScores, idx; |
countHighScores = CFArrayGetCount( prefCFArrayRef ); |
// print them out |
printf( "The high scores are:\n" ); |
for ( idx = 0;idx < countHighScores;idx++ ) { |
// get one of the high score elements |
CFArrayRef dataCFArrayRef; |
dataCFArrayRef = CFArrayGetValueAtIndex( prefCFArrayRef, idx ); |
if ( !dataCFArrayRef ) continue; |
// extract the players name... |
CFStringRef playerCFStringRef; |
playerCFStringRef = CFArrayGetValueAtIndex( dataCFArrayRef, 0 ); |
if ( !playerCFStringRef ) continue; |
char * playerStrPtr = Copy_CFStringRefToCString( playerCFStringRef ); |
if ( !playerStrPtr ) continue; |
// and their score |
SInt32 score = 0; |
CFNumberRef scoreCFNumber = CFArrayGetValueAtIndex( dataCFArrayRef, 1 ); |
if ( scoreCFNumber ) { |
if ( !CFNumberGetValue( scoreCFNumber, kCFNumberSInt32Type, &score ) ) { |
score = 0; |
} |
printf( "\t%ld\t\"%s\"\t%ld\n", idx, playerStrPtr, score ); |
} |
// free the player's string |
free( playerStrPtr ); |
} |
CFRelease( prefCFArrayRef ); |
} // HighScores_Dump |
// ***************************************************** |
// |
// Routine: HighScores_Update ( inPlayer, inScore ) |
// |
// Purpose: update the saved high scores |
// |
// Inputs: inPlayer - char * pointer to players name |
// inScore - SInt32 score |
// |
// Returns: TRUE if it's a new high score |
// |
static Boolean HighScores_Update( const char * inPlayer, SInt32 inScore ) |
{ |
CFArrayRef prefCFArrayRef = CFPreferencesCopyAppValue( kHighScoresKeyCFStr, kCFPreferencesCurrentApplication ); |
Boolean dirty = FALSE; |
if ( !prefCFArrayRef ) { // If they don't exist create a new empty array for high scores |
prefCFArrayRef = CFArrayCreate( kCFAllocatorDefault, NULL, 0, &kCFTypeArrayCallBacks ); |
dirty = TRUE; |
} |
// how many high scores are there? |
CFIndex countHighScores; |
countHighScores = CFArrayGetCount( prefCFArrayRef ); |
if ( countHighScores > kMaxNumHighScores ) { |
countHighScores = kMaxNumHighScores; |
} else if ( countHighScores < kMaxNumHighScores ) { |
dirty = TRUE; |
} |
CFArrayRef dataCFArrayRef = NULL; |
CFStringRef playerCFStringRef; // the player's name |
CFNumberRef scoreCFNumberRef; // the player's score |
// for each of the existing high scores |
UInt32 idx; |
for ( idx = 0; idx < countHighScores; idx++ ) { |
SInt32 score; |
// extract the high score data |
dataCFArrayRef = CFArrayGetValueAtIndex( prefCFArrayRef, idx ); |
if ( !dataCFArrayRef ) break; |
// extract the score |
scoreCFNumberRef = CFArrayGetValueAtIndex( dataCFArrayRef, 1 ); |
if ( !CFNumberGetValue( scoreCFNumberRef, kCFNumberSInt32Type, &score ) ) |
score = 0; |
if ( score < inScore ) // if our score is higher than this score... |
break; |
} |
// if dirty ( new array or count < max ) or our score is higher than a score in the list |
if ( dirty || ( idx < countHighScores ) ) { |
void * data[2]; |
// create player name & score CF types |
playerCFStringRef = CFStringCreateWithCString( kCFAllocatorDefault, inPlayer, kCFStringEncodingASCII ); |
scoreCFNumberRef = CFNumberCreate( kCFAllocatorDefault, kCFNumberSInt32Type, &inScore ); |
data[0] = ( void * ) playerCFStringRef; |
data[1] = ( void * ) scoreCFNumberRef; |
// create an array of the name / score pair |
dataCFArrayRef = CFArrayCreate( kCFAllocatorDefault, ( void * ) data, 2, &kCFTypeArrayCallBacks ); |
CFRelease( playerCFStringRef ); |
CFRelease( scoreCFNumberRef ); |
// create a mutable copy of our high score array |
CFMutableArrayRef tCFMutableArrayRef; |
tCFMutableArrayRef = CFArrayCreateMutableCopy( kCFAllocatorDefault, kMaxNumHighScores, prefCFArrayRef ); |
// If we're replacing the last entry delete it first |
if ( countHighScores == kMaxNumHighScores ) { |
CFArrayRemoveValueAtIndex( tCFMutableArrayRef, kMaxNumHighScores - 1 ); |
} |
// insert our new name / score / date pair into the prefs array |
CFArrayInsertValueAtIndex( tCFMutableArrayRef, idx, dataCFArrayRef ); |
CFRelease( dataCFArrayRef ); |
CFPreferencesSetAppValue( kHighScoresKeyCFStr, tCFMutableArrayRef, kCFPreferencesCurrentApplication ); |
CFRelease( tCFMutableArrayRef ); |
dirty = CFPreferencesAppSynchronize( kCFPreferencesCurrentApplication ); |
} |
CFRelease( prefCFArrayRef ); |
return dirty; |
} // HighScores_Update |
// ***************************************************** |
// |
// Routine: HighScores_Reset ( ) |
// |
// Purpose: reset the saved high scores |
// |
// Inputs: none |
// |
// Returns: TRUE if successful |
// |
static Boolean HighScores_Reset( void ) |
{ |
// NULL is passed to delete this preference |
CFPreferencesSetAppValue( kHighScoresKeyCFStr, NULL, kCFPreferencesCurrentApplication ); |
return CFPreferencesAppSynchronize( kCFPreferencesCurrentApplication ); |
} // HighScores_Reset |
Copyright © 2010 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2010-05-12