1. Trang chủ
  2. » Công Nghệ Thông Tin

Lập trình Wrox Professional Xcode 3 cho Mac OS part 64 docx

7 164 0

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 7
Dung lượng 2,1 MB

Nội dung

484 ❘ CHAPTER 18 DEBUGGING To delete an expression, select it in the Expressions window and press the Delete key. Expressions are very useful for examining the contents of array values. An expression like stack[1] examines the second element in the stack array. The expression buffer[index] examines whichever element the variable index refers to. DATA FORMATTERS The summary column in the variables pane is designed to present a compact, informative explanation of the value or object. For some objects, like strings, the summary value is obvious. For objects like a collection it might display the size of the collection — not a lot of detail, but still informative. For an opaque FSRef structure, it might convert that structure into a readable fi lename — very informative, indeed. This descriptive transformation is done using data formatters. Xcode includes many data formatters, but they won ’ t help with any object that you defi ne. You can create your own data formatters to summarize complex data structures and objects in the debugger. Creating a Custom Data Formatter Creating your own data formatters is very easy. It is really nothing more than a format string with placeholders for values or expressions derived from the variable being summarized. Any regular text in the data formatter is displayed verbatim. There are two kinds of placeholders: references and expressions. References are delimited by two percent characters ( %reference% ). A reference can refer to a single member variable by name. If the variable is contained in a substructure, use the appropriate period (.) separated variable name. You cannot use operators such as pointer dereferences or array indexes. For that, you need to use an expression. Taking the class that ’ s defi ned in Listing 18 - 3, the reference to the integer record_no of DataBlock class would be %header.record_no% . LISTING 18 - 3: Sample class typedef struct { int record_no; unsigned long checksum; } BlockHeader; @interface DataBlock : NSObject { @public BlockHeader header; NSMutableData* data; } An expression is any debugger expression; the same kind of expression that you can add to the Expressions window. In fact, it ’ s good to think of an expression in a data formatter as an expression in the Expressions window, as you ’ ll see in moment. Expressions are contained between matching braces ( { expression } ). Unlike references, expressions do not assume the context of the value being examined. To refer to the object being examined, use c18.indd 484c18.indd 484 1/22/10 12:55:49 PM1/22/10 12:55:49 PM Download at getcoolebook.com the $VAR macro in the expression. $VAR will be replaced with the name of the variable when the data formatter is evaluated. Using the previous class as an example again, the expression to access the record_no value would be {$VAR.header.record_no} . If you ’ re now guessing that you can refer to other variables in the context of the current stack frame, you ’ re correct. However, this isn ’ t a good idea, which is explained later. Limit your evaluation to the structure or object being examined. The advantage of expressions over references is that they are more expressive. You can perform math, include conditionals, and even call member functions. Again using the class defi ned in Listing 18 - 3, here are some valid expressions: {$VAR.header.record_no} {$VAR.header.checksum & 0x0000ffff} {$VAR.data?(int)[$VAR.data length]:0} Combining these two techniques, you can now create a data formatter for the DataBlock object type. Start by running the program and stopping the debugger with an instance of the DataBlock class in scope. Make sure that Run ➪ Variables View ➪ Enable Data Formatters is checked. Select the DataBlock variable in the variables pane and choose the Run ➪ Variables View ➪ Edit Summary Format. The debugger lets you edit the data formatter for the variable. Now you can enter the data formatter string shown in Figure 18 - 31. ➤ ➤ ➤ FIGURE 18-32 FIGURE 18-31 After it has been entered, this text becomes the data formatter used for every instance of the DataBlock class. The debugger resolves the references and expressions for each instance, creating the more informative summary shown in Figure 18 - 32. The syntax used for references and expressions can be extended to obtain other information about the value or expression. The fi nal display value can be something different from the value to which the expression evaluates. The other types of information that can be extracted from an expression are chosen using one of the column selectors listed in the following table. The “ column ” Data Formatters ❘ 485 c18.indd 485c18.indd 485 1/22/10 12:55:50 PM1/22/10 12:55:50 PM Download at getcoolebook.com 486 ❘ CHAPTER 18 DEBUGGING you are selecting is one of the columns in the variables pane or the Expressions window. In essence, the result of a reference or expression is treated as if it had been entered into the Expressions window. The column selector lets you choose which column in the window will be used as the result of the expression. You can think of an expression result as an object with four properties (value, name, type, and summary) — the column selector lets you choose which property to display. COLUMN SELECTOR DESCRIPTION { expression }:v , % reference %:v The value of the expression — that is, the primitive numerical value that would appear in the Value column of the Expressions window. This is the default column. Omitting the column selector is equivalent to using :v . { expression }:t , % reference %:t The type of the fi nal data object to which the expression evaluates. A numerical expression would result in a primitive data type, such as int or double. The type of an expression that refers to a member variable, or calls a function, will be the type of the expression ’ s result. For example, the expression {[$VAR owner]}:t would display the type of the object returned by the method owner. { expression }:s , % reference %:s This selector results in the text that would appear in the Summary column of the expression. Because the Summary column can be formed using data formatters, this is a way of using other data formatters in portions of your data formatter. You can only use this on expressions that have a summary display. Expressions that result in primitive values do not have any content in their Summary column. { expression }:n , % reference %:n The name of the variable or expression that would appear in the Expression column of the Expressions window. The column is self - referential and not particularly useful. The type column ( :t ) can be useful for displaying the type or class of a member value. For example, if you have a class that manages a collection of homogenous objects, a data formatter of collection of {[$VAR lastObject]}:t would tell you what kind of objects your collection contains. The summary column selector is the most useful. You can use it to construct data formatters from other data formatters. To get a feel for creating your own data formatters, look at the following example. Let ’ s assume you have a project with the DataBlock class shown in Listing 18 - 3, and a subclass named StampedDatablock, shown in Listing 18 - 4. LISTING 18 - 4: DataBlock subclass @interface StampedDataBlock : DataBlock { @private NSCalendarDate* createdDate; NSCalendarDate* modifiedDate; } c18.indd 486c18.indd 486 1/22/10 12:55:51 PM1/22/10 12:55:51 PM Download at getcoolebook.com To create a custom data formatter for these two classes, follow these steps: 1. Build the application, start it under the control of the debugger, and stop at a breakpoint where a DataBlock and StampedDataBlock object are in scope, as shown in Figure 18 - 33. 2. Set the data formatter for the block variable to record %header.record_no%, {(int)[$VAR.data length]} bytes . 3. Set the data formatter for the trackedBlock variable to {(DataBlock*)$VAR}:s, created %createdDate%:s . 4. Continue stepping through the program. FIGURE 18-33 The fi rst data formatter created for the DataBlock class summarizes its contents by accessing its record_no and data instance variables. The debugger now presents a much friendlier summary of the object ’ s state. The StampedDataBlock formatter is a little trickier. The StampedDataBlock class does not inherit the data formatter for DataBlock. Data formatters for each type are independent of one another. Two problems are inherent in creating a data formatter for the new subclass. First, you don ’ t want to repeat everything you wrote for the DataBlock formatter. Secondly, you don ’ t want to write a formatter for the NSCalendarDate member object. The summary column selector lets you avoid both of these problems by setting the data formatter for the StampedDataBlock class to {(DataBlock*)$VAR}:s, created %createdDate%:s . The fi rst expression casts the object to an instance of its superclass and obtains text that would appear in its Summary column, effectively calling the data formatter you created for the DataBlock class. The second reference obtains the value of createdDate and inserts what would appear in its Summary column, essentially using Xcode ’ s built - in data formatter. The fi nal result, shown in Figure 18 - 34, is a data formatter that extends the data formatter of its superclass using a built - in data formatter supplied by Xcode. Data Formatters ❘ 487 c18.indd 487c18.indd 487 1/22/10 12:55:52 PM1/22/10 12:55:52 PM Download at getcoolebook.com 488 ❘ CHAPTER 18 DEBUGGING Troubleshooting Data Formatters Data formatters can be very useful during debugging. You can create data formatters that quickly summarize the state of complex objects. This allows you to concentrate on the high - level logic of your application, rather than spending all of your time digging through the member variables of objects trying to decode their content. Writing data formatters, however, can be a frustrating experience. If there is anything the debugger doesn ’ t like about your data formatter, it won ’ t use it. The following table lists some of the more common problems you can encounter while creating data formatters: TYPE OF PROBLEM SOLUTION Syntax Be extra careful about the syntax of your expressions and references. Quotes Double quotes in the body of an expression must be escaped with a backslash. Example: name “ {[$VAR getProperty:\ “ name\ “ ]}:s ” . Notice that the quotes inside the expression are escaped, but not in the text outside the expression. Unknown types The debugger often does not know the data type of values returned by functions. If you have any doubts, cast the result: author {(NSString*)[$VAR authorName]}:s Execution problems Expressions that call functions have to function perfectly. The formatter name {[$VAR name]}:s will fail if the method name throws an exception, tries to access a NULL variable, can ’ t allocate memory, or any of a limitless number of similar run time problems. The functions that you call using data formatters should be extremely defensive. Null summary You cannot use the :s column selector if the expression results in a data type that has no summary column content. Invalid references Expressions that use other variables in the current stack frame context will fail when interpreted in a di erent stack frame or execution context where those variables don ’ t exist. Data formatters should concern themselves only with examining the contents of the structure or object. FIGURE 18-34 c18.indd 488c18.indd 488 1/22/10 12:55:53 PM1/22/10 12:55:53 PM Download at getcoolebook.com TYPE OF PROBLEM SOLUTION ZeroLink, dynamically loaded libraries This is yet one more situation where dynamically loaded libraries can trip you up. Expressions executed in the debugger will not cause unreferenced symbols to load. If your application hasn ’ t caused a symbol or function to load yet, a data formatter that uses that function or type will fail. Temporary Objects (For Objective - C programmers) Be warned that creating auto - released objects in your data formatters may result in memory leaks. An example would be {(NSString*)[NSString stringWithCharacters: $VAR.uStr.unicode length:$VAR.uStr.length] }:s . The problem here is that the NSString object is created in the context of the debugger and has no auto - release pool. You will see a “ leak ” message in the debugger log. Side E ects Data formatters can call functions in your application. Side e ects, such as altering instance variables or releasing objects, can have unexpected consequences in your application and your debugging e orts. If you are having problems getting a formatter to work, break it down into its individual components and subexpressions and try each one at a time. Slowly build up the expression until you get it working or fi nd the element that thwarts your efforts. Try expressions without the column selector. Cast return values liberally. Replace macros and function calls with constants. Turn off ZeroLink. Add the same function call to your code and try debugging it. Data formatters you defi ne are stored in the ~/Library/Application Support/Apple/Developer Tools/CustomDataViews/CustomDataViews.plist fi le. Data formatters are global to all projects and are not stored in the project document. Sharing data formatters with other developers will require some copying and pasting, or you may just want to exchange CustomDataViews.plist fi les. Beyond Data Formatter Strings Although data formatters can do a lot, they are limited to what can be expressed in a format string. If you need a data formatter that exceeds these capabilities, you can develop your own data formatter plug - in. The descriptions for doing so are in the DataFormatterPlugin.h fi le, buried inside the Xcode application itself at /Developer/Applications/Xcode.app/Contents/PlugIns/ GDBMIDebugging.xcplugin/Contents/Headers/DataFormatterPlugin.h . This fi le contains detailed information about formatter strings, the format of CustomDataViews.plist , and how to create a data formatter plug - in, among other topics. In brief, you create a data formatter plug - in by creating a bundle. The bundle contains its own CustomDataViews.plist fi le. Unlike data formatter strings that you type into the debugger window, the data formatter strings in the bundle ’ s CustomDataViews.plist fi le can call any of the functions defi ned in the plug - in bundle. The sample ManagedObjectDataFormatter project produces a data formatter plug - in for managed objects. You can fi nd it by searching the Xcode documentation for ManagedObjectDataFormatter. Use this project as a template for creating your own data formatter plug - ins. Data Formatters ❘ 489 c18.indd 489c18.indd 489 1/22/10 12:55:54 PM1/22/10 12:55:54 PM Download at getcoolebook.com 490 ❘ CHAPTER 18 DEBUGGING Object Descriptions Like data formatters, many object - oriented languages have adopted conventions for converting any object into a textual representation. In Java, this is the toString() function. Objective - C uses the - [NSObject description] method. If you are using an object that supports one of these standards, you can use the Run ➪ Variables View ➪ Print Description to Console command. The debugger invokes the standard “ to string ” function on the object and sends the result to the debugger console. WATCHPOINTS Watchpoints are breakpoints for data. You can make any variable a watchpoint. Whenever the debugger detects that the value of that variable has changed, it stops your application. Watchpoints sound great, but they are fairly limited. The biggest problem is that your application can ’ t execute any code where the watchpoint variable is out of context, so they are mostly useful for global variables that are always in scope and for catching state changes in a loop. You set a watchpoint by fi rst selecting a variable in the variables pane. Choose the Run ➪ Variables View ➪ Watch Variable command. This places a magnifying glass icon next to the variable as shown in Figure 18 - 35. Start the program executing again, and it breaks at the point just before the variable is altered with a dialog box explaining what is about to happen, also shown in Figure 18 - 35. FIGURE 18-35 You can choose to acknowledge the event and leave the watchpoint set, or disable the watchpoint by clicking the Disable button. Watchpoints are automatically deleted whenever your application exits the context where the watchpoint variable exists. Watchpoints are not retained between debug sessions. You can create an effect similar to a watchpoint using a breakpoint conditional like i!=0 . It ’ s not as convenient as a watchpoint, but it ’ s more durable. To remove a watchpoint, select the variable being watched and choose Run ➪ Variables View ➪ Watch Variable again to remove the check mark. c18.indd 490c18.indd 490 1/22/10 12:55:54 PM1/22/10 12:55:54 PM Download at getcoolebook.com . and choose the Run ➪ Variables View ➪ Edit Summary Format. The debugger lets you edit the data formatter for the variable. Now you can enter the data formatter string shown in Figure 18 - 31 are in scope, as shown in Figure 18 - 33 . 2. Set the data formatter for the block variable to record %header.record_no%, {(int)[$VAR.data length]} bytes . 3. Set the data formatter for the trackedBlock. those variables don ’ t exist. Data formatters should concern themselves only with examining the contents of the structure or object. FIGURE 18 -34 c18.indd 488c18.indd 488 1/22/10 12:55: 53 PM1/22/10

Ngày đăng: 04/07/2014, 06:20