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 167 0
Tài liệu đã được kiểm tra trùng lặp

Đ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

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

DATA FORMATTERS The summary column in the variables pane is designed to present a compact, informative explanation of the value or object.. Again using the class defi ned in Listing 18

Trang 1

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

Trang 2

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

Trang 3

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

{ 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;

}

Trang 4

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

Trang 5

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:

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 diff 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

Trang 6

T YPE 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 Eff ects Data formatters can call functions in your application Side eff ects, such

as altering instance variables or releasing objects, can have unexpected consequences in your application and your debugging eff 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

Trang 7

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

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