您的位置:首页 > 其它

Brief Intro to Foundation Functions

2013-11-22 13:38 561 查看
Foundation Functions
The Foundation Framework defines a number of functions and function-like macros. The Apple Foundation Functions Reference provides a definitive guide for these functions.
Here you’ll examine Foundation functions that perform the following tasks:

Assertions and logging
String localization
Numerical operations and byte ordering
Runtime operations

Assertions
An assertion is a statement placed in code to check the existence of a condition. Assertions are used to provide
runtime verification of assumptions that, if not present, should cause the program to terminate. Coding with assertions is one of the quickest and most effective ways to detect and correct bugs. Assertions can also document the logic of your program, thereby
enhancing maintainability.
Each assertion contains a Boolean expression that you believe will be true when the assertion executes. If it is not true, the system will throw an error. By verifying
that the expression is indeed true, the assertion confirms your assumptions about the behavior of your program, increasing your confidence that the program is free of errors.
The following are examples of situations where you would use assertions:

Internal invariant: An assumption concerning program behavior. This assumption is often indicated with comments in code, but it can be documented and validated at runtime with an assertion.
Control-flow invariant: An assumption concerning control flow, specifically locations in your code that should not be reached.
Precondition: A condition that must be true before a method is invoked.
Postcondition: A condition that must be true after a method is invoked.
Class invariant: A condition that must be true for each class instance.

An example of an internal invariant is the conditional expression in

Listing 13-1.
Listing 13-1. Example of a Conditional
Expression with an Internal Invariant
if (value >= 0)
{
...
}
else
{
// value must be negative
...
}

As shown in
Listing 13-1, these assumptions are often indicated with comments in code, but can be documented and validated at runtime with an assertion. The code excerpt from

Listing 13-1 is updated in
Listing 13-2 to express the invariant with an assertion.
Listing 13-2. Example of an Internal
Invariant Expressed with an Assertion
if (value >= 0)
{
...
}
else
{
NSAssert((value < 0), @"Value not valid here, should be negative");
...
}

A common type of precondition is a conditional check of the input parameters for a method (or function). For public methods, preconditions are explicitly checked
in code and throw the appropriate exception if the condition is not satisfied, hence they should not be checked with assertions. Assertions can be used to check preconditions for private methods and functions.
Assertions can be used to test postconditions for both public and private methods/functions.
A class invariant constrains the properties (i.e., internal state) and behavior of each instance of a class. Assertions can be used to define class invariants
in a manner similar to that used to express the other situations discussed earlier.

Assertion Macros
The Foundation assertion functions are, in fact, macros that enable the creation of assertions in Objective-C code. Each assertion macro evaluates a condition and,
if the condition evaluates to false, passes a string (and possibly additional printf-style arguments formatted into the string) describing the failure to an
NSAssertionHandler instance.
NSAssertionHandler is a Foundation Framework class used to handle false assertions, and each program thread has its own
NSAssertionHandler object. So, when the condition of a Foundation assertion macro evaluates to false, it passes the condition describing the error to the
NSAssertionHandler object for the current thread. This object in turn logs the error and then raises an exception (specifically, an
NSInternalIncosistencyException) that causes the program to terminate.
NSAssertionHandler instances are generally not created programmatically, but rather by an assertion function.
There are multiple Foundation assertion macros to support the creation of assertions within Objective-C methods
and functions. Each assertion macro has at least one argument: a conditional expression that evaluates to true or false. Most also include an argument that contains a format string describing the error condition.
The assertion macros support the substitution of zero to five arguments in a format string. The complete list of Foundation assertions functions is provided in

Table 13-1.

Table 13-1.
Foundation Assertion Functions
Foundation FunctionDescription
NSAssertGenerates an assertion for an Objective-C method if a given condition evaluates to
NO (false). Its arguments include the conditional expression and a format string (with no format specifier) that describes the error.
NSAssert1Similar to NSAssert, its arguments include the conditional expression, a format string (with one format specifier), and an argument to be inserted into the format string.
NSAssert2,
NSAssert3, NSAssert4,
NSAssert5
Similar to NSAssert, its arguments include the conditional expression, a format string (with two, three, four, or five format specifiers), and two, three, four, or five arguments to be inserted
into the format string.
NSParameterAssertGenerates an assertion for the parameter of an Objective-C method. Its arguments are the conditional expression for a parameter.
NSCAssertGenerates an assertion
for an Objective-C function: if a given condition evaluates to
NO (false). Its arguments include the conditional expression and a format string (with no format specifier) that describes the error.
NSCAssert1Similar to NSCAssert, its arguments include the conditional expression, a format string (with one format specifier), and an argument to be inserted into the format string.
NSCAssert2,
NSCAssert3, NSCAssert4,
NSCAssert5
Similar to NSCAssert, its arguments include the conditional expression, a format string (with two, three, four, or five format specifiers), and two, three, four, or five arguments to be inserted
into the format string.
NSCParameterAssertGenerates an assertion for the parameter of an Objective-C function. Its arguments are the conditional expression for a parameter.
The following statement uses the
NSAssert function to assert that the value of the variable named
age is within the prescribed range.
NSAssert((age > 0) && (age <=18), @"Variable age not within prescribed range");

In the next statement, the same assertion is performed again, this time using the
NSAssert1 function to log the value of the variable if the assertion fails.
NSAssert1((age > 0) && (age <=18),
@"Value %d for age not within prescribed range", age);

Assertions can be used to check parameters of private methods or functions. Parameter
checking for public methods/functions is normally part of the corresponding published API; hence, these should be checked whether or not assertions are enabled.

Listing 13-3 uses the NSParameterAssert function to assert that the parameters for the method
encodeArchive:toFile: have valid values.
Listing 13-3. Asserting
Method Parameter Values Using NSParameterAssert
- (BOOL) encodeArchive:(id)objectGraph toFile:(NSString *)file
{
NSParameterAssert(file != nil);
NSParameterAssert([objectGraph conformsToProtocol:@protocol(NSCoding)]);
...
}

You can disable assertions in your code by defining the preprocessor macro;
NS_BLOCK_ASSERTIONS, for example.
#define NS_BLOCK_ASSERTIONS


Logging
The Foundation Framework includes two functions,
NSLog and NSLogv, for logging output to the system log facility. In Xcode, error messages from these functions are displayed in the Xcode output
pane. By now you have become familiar with the NSLog function through the example source code provided in this book, so here you’ll examine the
NSLogv function.
NSLogv, as with
NSLog, logs an error message to the system log facility.
It differs from NSLog in that it supports a variable argument list.
The declaration for the NSLog function is
void NSLogv(NSString *format, va_list args);

The variable
format is a format string, and the variable
args is a data type used for providing a list of (variable) arguments to functions. So you may be wondering, when would you use
NSLogv?
If you have a method or function that takes a variable argument list, then
NSLogv can be used to log messages with this list. For example, the
variadic function
printArgs declared as follows:
void printArgs(int numArgs, ...);

logs a number of function arguments to the system log facility, where the arguments are a variable list (specified by the
... variable argument symbol) and the number of arguments from this list to be logged (specified by the
numArgs function argument). Given this function declaration,

Listing 13-4 demonstrates how this function is implemented using the
NSLogv function.
Listing 13-4. Using
NSLogv to Log a variadic Argument List
void printArgs(int numArgs, ...)
{
va_list args;
va_start(args, numArgs);
va_end(args);
NSMutableString *format = [[NSMutableString alloc] init];
[format appendString:@"Arguments: "];
for (int ii=0; ii<numArgs-1; ii++)
{
[format appendString:@"%@, "];
}
if (numArgs > 1)
{
[format appendString:@"%@"];
}
NSLogv(format, args);
}

If this function is invoked as follows:
printArgs(3, @"Hello", @"Objective-C", @"World!");

It logs to the console the following message:
Arguments: Hello, Objective-C, World!


Bundles
The Foundation Framework includes several function macros for retrieving localized strings. They are used to load strings from a program’s strings files. Before you
begin examining these macros, let’s take a moment to discuss internationalization and localization.
Internationalization is the process of designing an application so that it can serve different languages and regions (i.e., locales) without being changed.
Localization is the adaptation of an internationalized application to a local market. Localization can be applied to many parts of an application, including its visible text, icons and graphics, views,
and data.

Localizing Strings
Localizing visible text is a key part of the localization process.
Strings in code that require localization must be extracted, localized, and reinserted back in the code in order to display properly in
the specified locale. Apple provides a tool, genstrings, which can be used to facilitate text localization. The
genstrings tool searches your code for uses of the localization function macros and uses the information they contain to build the initial set of
strings files (resource files that contain localizable strings) for your application. For example, if your source code contains a
statement that utilizes the localization function macro
NSLocalizedString to return a localized version of the string
Yes, as follows:
NSString *yes = NSLocalizedString(@"Yes", @"Word for yes");

the genstrings tool will parse this statement and use it to build a strings file. The genstrings tool can parse C and Objective-C source code files with the
.c or .m filename extensions. You can also specify the output directory where genstrings places the resulting strings files. In most cases, you
would want to specify the directory containing the project resources for your development language.
The following example uses the genstrings tool to parse all Objective-C source files in the current directory and store the resulting strings file in the
en.lproj subdirectory, which must already exist.
genstrings -o en.lproj *.m

The first time you run the genstrings tool, it creates a set of new strings files for you. Subsequent executions on the sme file(s) replace the contents of those strings
files with the current string entries found in your source code.

Localized Strings Functions
Once you have localized strings in a strings file, the Foundation localized string function macros can be used to retrieve the appropriate localized string
for a specified locale. The Foundation Framework defines four function macros for getting localized strings, shown in

Table 13-2.

Table 13-2.
Foundation Localized String Functions
Foundation FunctionDescription
NSLocalizedStringRetrieves a localized version of a string on the main application bundle in the default strings table.
NSLocalizedStringFromTableRetrieves a localized version of a string on the main application bundle in the specified strings table.
NSLocalizedStringFromTableInBundleRetrieves a localized version of a string on the specified application bundle and strings table.
NSLocalizedStringWithDefaultValueRetrieves a localized version of a string on the specified application bundle and strings table, using the default value if the key is not found.
The localized string functions depend on an
NSBundle class instance. Each function invokes an
NSBundle object’s
localizedStringForKey:value:table: method, providing the function arguments as parameters for the method.
So, the localization functions both provide expressions that can be parsed by the genstrings tool to create an application’s strings
file, and retrieve a localized version of a string. They also let you associate translation comments with each entry.
For example, if your program has a
strings table in a file named
Localizable.strings that includes the following strings:
"Yes" = "Yes"
"No" = "No"

the
NSLocalizedStringFromTable function would retrieve the string
Yes with the following statement.
NSString *yes = NSLocalizedStringFromTable(@"Yes", @"Localizable.strings",
@"Word for yes");

Conversely, if the
Localizable.strings file for the French locale contained the values
"Yes" = "Oui"
"No" = "Non"

Then the preceding statement would retrieve the string
Oui.

Decimal Numbers and Byte Ordering
The Foundation Framework includes functions for performing decimal number operations. The arithmetic operations supported include decimal arithmetic,
rounding, comparison, copy, normalizing, and string representations.
The functions take one or more
NSDecimal numbers as arguments, along with (potentially) other parameters.
NSDecimal is a Foundation data type
used to describe a decimal number.
NSDecimalAdd,
NSDecimalSubtract,
NSDecimalMultiply, and NSDecimalDivide perform the associated arithmetic operations on
NSDecimal instances.
NSDecimalMultiplyByPowerOf10 multiplies a number by an input power of 10. Each takes as an input argument an
NSRoundingMode Foundation constant that specifies how the result is rounded. The available rounding modes are:

NSRoundDown: Rounds the returned value down.
NSRoundUp: Rounds the returned value up.
NSRoundPlain: Rounds to the closest possible return value.
When the value is halfway between two positive numbers, it rounds up. When the value is halfway between two negative numbers, it rounds down.
NSRoundBankers: Rounds to the closest possible return value. When the value is halfway between two numbers, it returns
the value whose last digit is even.

Rounding can be explicitly performed using the
NSDecimalRound function, or automatically performed for the
NSDecimal arithmetic functions if the result has more digits than the maximum number of significant digits allowed (38).
NSDecimalPower raises a number to the specified power.
NSDecimalNormalize and
NSDecimalCompact both change the representation of a decimal number.
NSDecimalCompact formats a decimal so that it takes up the minimum amount of memory. All of the
NSDecimal functions expect compact decimal arguments.
NSDecimalNormalize updates the format of its two decimal arguments such that they have the same exponent.
NSDecimalAdd and
NSDecimalSubtract invoke NSDecimalNormalize.
NSDecimalRound rounds the input decimal according to the input
NSRoundingMode constant.
NSDecimalCopy copies the value of a decimal number to another
NSDecimalNumber instance.
NSDecimalCompare compares two decimal numbers, returning the result of the comparison as an
NSComparisonResult value (a Foundation constant) that can have one of the following values:

NSOrderedDescending: The left operand is greater than the right operand.
NSOrderedAscending: The left operand is less than the right operand.
NSOrderedSame: The two operands are equal.

Using the NSDecimal Functions
Now you’ll create a program that demonstrates the use of the Foundation decimal arithmetic functions. In Xcode, create a new project by selecting
New

Project . . .
from the Xcode File menu. In the
New Project Assistant pane, create a command-line application. In the Project Options window, specify
DecimalAddition for the Product Name, choose Foundation for the Project Type, and select ARC memory management by selecting the
Use Automatic Reference Counting check box. Specify the location in your file system where you want the project to be created (if necessary select
New Folder and enter the name and location for the folder), uncheck the
Source Control check box, and then click the Create button.
OK, the
DecimalAddition project is created. Now select the main.m file and update the
main() function, as shown in
Listing 13-5.
Listing 13-5. Performing
Decimal Arithmetic Using the NSDecimalAdd and NSDecimalRound Functions
#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{
@autoreleasepool
{
// Create two NSDecimal numbers using the NSDecimalNumber class
NSDecimal dec1 = [[NSDecimalNumber decimalNumberWithString:@"1.534"]
decimalValue];
NSDecimal dec2 = [[NSDecimalNumber decimalNumberWithString:@"2.011"]
decimalValue];

// Declare result and rounded result variables for the calculations
NSDecimal result;
NSDecimal roundedResult;

// Now perform the decimal addition
NSDecimalAdd(&result, &dec1, &dec2, NSRoundPlain);
NSLog(@"Sum = %@", NSDecimalString(&result, nil));

// Demonstrate rounding the result using the available rounding modes
NSDecimalRound(&roundedResult, &result, 2, NSRoundUp);
NSLog(@"Sum (round up) = %@", NSDecimalString(&roundedResult, nil));
NSDecimalRound(&roundedResult, &result, 2, NSRoundDown);
NSLog(@"Sum (round down) = %@", NSDecimalString(&roundedResult, nil));
NSDecimalRound(&roundedResult, &result, 2, NSRoundPlain);
NSLog(@"Sum (round plain) = %@", NSDecimalString(&roundedResult, nil));
NSDecimalRound(&roundedResult, &result, 2, NSRoundBankers);
NSLog(@"Sum (round bankers) = %@", NSDecimalString(&roundedResult, nil));
}
return 0;
}

As shown in
Listing 13-5, the NSDecimalNumber class is used to create two decimal numbers of the
Foundation type NSDecimal. The
NSDecimalAdd function is then used to add the two numbers. Because the number of digits in the result is less than the maximum allowed, no rounding is performed and the result printed
by the NSLog function is 3.545. Next, the
NSDecimalRound function is used to explicitly round the result to two digits after the decimal point; each of the available rounding modes is used to demonstrate how they affect the result. When you compile and run
the program, you should observe messages in the output pane comparable to those shown in

Figure 13-1.



Figure 13-1.
DecimalAddition program output

As you can see in

Figure 13-1, the selected rounding mode affects the result as explained earlier.
The
NSDecimalNumber class provides methods that duplicate much of the functionality of the
NSDecimal functions; hence, you have the choice of which to use to perform decimal arithmetic. The
NSDecimal functions provide better performance and lower memory utilization than the
NSDecimalNumber class. However, the
NSDecimalNumber class performs these decimal operations using objects, and enables you to directly store the results of these operations in an object-oriented collection like an instance of
NSArray or NSDictionary.

Byte Ordering
The Foundation Framework includes a set of functions that perform byte ordering; specifically, these functions can be used to swap the order of bytes of a number
as stored in memory. Byte ordering is important when a binary file created on one computer is read on another computer with a different byte order.
Big endian machines (such as a Motorola 680x0 CPU) store data with the most significant byte in the lowest memory address.
A little endian machine (such as an Intel CPU) stores the most significant byte in the highest memory address.
For example, the decimal value of 4132 (hexadecimal 1024) would be stored as shown in

Table 13-3.

Table 13-3.
Byte Ordering for Big Endian and Little Endian Machines



In order for binary files to be successfully transferred and processed between these big and little endian machines, the byte ordering of the data needs to
be swapped. The NSSwap byte ordering functions perform big to little and little to big endian byte ordering for the following data types: short,
int, long, long long, float, and double. The NSSwapHost functions swap from the current endian format to that specified for the input data type.
The NSHostByteOrder function determines the host endian format. It returns a Foundation constant value of
NS_LittleEndian or
NS_BigEndian.

Interacting with the Runtime
The Foundation Framework includes several functions that utilize the Objective-C runtime library. These functions enable dynamic operations.
The
NSGetSizeAndAlignment function is used to get the size of a character array in bytes. The following functions retrieve a string representation of a corresponding Objective-C type:

NSStringFromSelector
NSStringFromProtocol
NSStringFromClass

The following statement retrieves a text string (sayHello:) for a selector specified with
the @selector directive, and assigns this string to the variable
methodName.
NSString *methodName = NSStringFromSelector(@selector(sayHello:));

The next set of functions perform the converse operation; they retrieve an Objective-C type from a string representation:

NSSelectorFromString
NSProtocolFromString
NSClassFromString

The following statement dynamically retrieves a selector from the input string.
SEL methodSel = NSSelectorFromString(@"sayHello:");


File Paths
A set of Foundation functions provides operations for managing file paths, including retrieving the user name,
home directory, temporary directory, and directory search paths. The following statement demonstrates use of the
NSFullUserName function to retrieve the full name of the current user.
NSString *fullName = NSFullUserName();

The
NSUserName function, in comparison, returns the logon name of the current user.
The following statement demonstrates use of the
NSHomeDirectory function to retrieve the home directory for the current user.
NSString *homeDir = NSHomeDirectory();

The
NSHomeDirectoryForUser function retrieves the home directory for the user specified in the input argument.
The
NSTemporaryDirectory function retrieves the full path to the temporary directory for the current user.
The
NSSearchPathForDirectoriesInDomains function returns a list of directory search paths for the specified directories in the specified domains. The syntax for the function
is
NSSearchPathForDirectoriesInDomains(
NSSearchPathDirectory directory,
NSSearchPathDomainMask domainMask,
BOOL expandTilde);

The
NSSearchPathDirectory is a Foundation constant that specifies a variety of directories in the file system, for example the
Documents directory. The
NSSearchPathDomainMask
is a Foundation constant used to specify the domain for the search; for example, the user’s home directory. The
BOOL argument is set to
YES if the paths returned should be expanded.
Listing 13-6 demonstrates the use of the function to retrieve the documents directory
for the current user.
Listing 13-6. Retrieving
the Documents Directory Using the NSSearchPathForDirectoriesInDomains Function
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = paths[0];


Geometry
The Foundation Framework includes functions that assist in the performance of geometric calculations on points, ranges, rectangles, and sizes. A point represents a location
in two-dimensional Euclidean geometry with x and y coordinates. A
range represents a one-dimensional quantity beginning at a specified location of a specified length. A
size represents a two-dimensional quantity of specified width and height. The point, range, and size Foundation functions perform operations to create, retrieve, test for equality, and return string representations of
these quantities. The Foundation data types NSPoint represents points,
NSRange represents ranges, and
NSSize represents sizes. The following statement creates a new
NSPoint from the specified values.
NSPoint point = NSMakePoint(0, 5);

The Foundation framework also includes numerous functions for manipulating rectangles, including operations to create, get, get components, query, test for equality,
and return string representations. There are also functions that perform geometric operations (test for intersection, union, divide, point in rectangle, etc.). The Foundation data type
NSRect represents rectangles. The following statement creates a rectangle at point {0, 0} and size [5, 10].
NSRect rect1 = NSMakeRect(0.0, 0.0, 5.0, 10.0);

The next set of statements creates a new rectangle at point {2.5, 5} and size [5, 10], and then calculates the intersection of the two rectangles.
NSRect rect2 = NSMakeRect(2.5, 5.0, 5.0, 10.0);
NSRect rect3 = NSIntersectionRect(rect1, rect2);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: