Brief Intro to Foundation Functions

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, NSAssert5Similar 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, NSCAssert5Similar 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 image 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.

9781430250500_Fig13-01.jpg

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

table

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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
图像识别技术在病虫害检测中的应用是一个快速发展的领域,它结合了计算机视觉和机器学习算法来自动识别和分类植物上的病虫害。以下是这一技术的一些关键步骤和组成部分: 1. **数据收集**:首先需要收集大量的植物图像数据,这些数据包括健康植物的图像以及受不同病虫害影响的植物图像。 2. **图像预处理**:对收集到的图像进行处理,以提高后续分析的准确性。这可能包括调整亮度、对比度、去噪、裁剪、缩放等。 3. **特征提取**:从图像中提取有助于识别病虫害的特征。这些特征可能包括颜色、纹理、形状、边缘等。 4. **模型训练**:使用机器学习算法(如支持向量机、随机森林、卷积神经网络等)来训练模型。训练过程中,算法会学习如何根据提取的特征来识别不同的病虫害。 5. **模型验证和测试**:在独立的测试集上验证模型的性能,以确保其准确性和泛化能力。 6. **部署和应用**:将训练好的模型部署到实际的病虫害检测系统中,可以是移动应用、网页服务或集成到智能农业设备中。 7. **实时监测**:在实际应用中,系统可以实时接收植物图像,并快速给出病虫害的检测结果。 8. **持续学习**:随着时间的推移,系统可以不断学习新的病虫害样本,以提高其识别能力。 9. **用户界面**:为了方便用户使用,通常会有一个用户友好的界面,显示检测结果,并提供进一步的指导或建议。 这项技术的优势在于它可以快速、准确地识别出病虫害,甚至在早期阶段就能发现问题,从而及时采取措施。此外,它还可以减少对化学农药的依赖,支持可持续农业发展。随着技术的不断进步,图像识别在病虫害检测中的应用将越来越广泛。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值