Detail Pane Extended Detail Pane Track Pane Instruments Pane FIGURE A - 2: The trace document The Instruments pane shows the list of instruments that you are using for the current tra
Trang 1NSLog (@”connection:didReceiveData:”);
// Append the received data to our responseData property [self.responseData appendData:data];
}
TermExtractViewController.m
Now you need to implement connectionDidFinishLoading The delegate calls this method when the connection has completed loading the requested data In this method, you convert the response data to a string, clean up the connection, and call the method to parse the XML:
// Called when the connection has successfully received the complete response
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog (@”connectionDidFinishLoading:”);
// Convert the data to a string and log the response string NSString *responseString = [[NSString alloc]
initWithData:self.responseData encoding:NSUTF8StringEncoding];
NSLog(@”Response String: \n%@”, responseString);
[responseString release];
[connection release];
[self parseXML];
}
TermExtractViewController.m
Finally, you should implement the connection:didFailWithError: method Here you will log that an error occurred In a production application, you would want to provide more robust error handling Here is the implementation:
// Called when an error occurs in loading the response
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{ NSLog (@”connection:didFailWithError:”);
NSLog (@”%@”,[error localizedDescription]);
[connection release];
}
TermExtractViewController.m
Trang 2340 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES
Parsing the Response XML
After you submit your request, you will receive an XML response from the web service The
response will contain the most relevant words and phrases from the text that you sent into
the service, in order of relevance The response that I received when I sent the declaration to the
web service looked like this:
< ?xml version=”1.0”? >
< ResultSet xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns=”urn:yahoo:cate” xsi:schemaLocation=”urn:yahoo:cate
http://search.yahooapis.com/ContentAnalysisService/V1/
TermExtractionResponse.xsd” >
< Result > life liberty and the pursuit of happiness < /Result >
< Result > powers of the earth < /Result >
< Result > liberty and the pursuit of happiness < /Result >
< Result > pursuit of happiness < /Result >
< Result > certain unalienable rights < /Result >
< Result > absolute despotism < /Result >
< Result > political bands < /Result >
< Result > transient causes < /Result >
< Result > decent respect < /Result >
< Result > long train < /Result >
< Result > direct object < /Result >
< Result > usurpations < /Result >
< Result > sufferance < /Result >
< Result > laws of nature < /Result >
< Result > one people < /Result >
< Result > form of government < /Result >
< Result > when in the course of human events < /Result >
< Result > evils < /Result >
< Result > prudence < /Result >
< Result > mankind < /Result >
< /ResultSet >
You need to implement the parseXML function, just as you did in the previous example, to parse this
response XML:
- (void) parseXML {
NSLog (@”parseXML”);
// Initialize the parser with our NSData from the RSS feed
NSXMLParser *xmlParser = [[NSXMLParser alloc]
initWithData:self.responseData];
// Set the delegate to self
[xmlParser setDelegate:self];
// Start the parser
if (![xmlParser parse])
{
NSLog (@”An error occurred in the parsing”);
}
Trang 3
// Release the parser because we are done with it [xmlParser release];
}
TermExtractViewController.m
In this method, you fi rst declare an instance of an NSXMLParser and initialize it with the response data that you received from the web service Next, you set the parser ’ s delegate to self Then, you tell the parser to start parsing the XML Finally, you release the parser
Finally, you will implement your NSXMLParser delegate methods:
// Called when the parser encounters a start element
- (void) parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qualifiedName attributes:(NSDictionary *)attributeDict {
// Check to see which element we have found
if ([elementName isEqualToString:@”Result”]) { // Initialize the capturedCharacters instance variable capturedCharacters = [[NSMutableString alloc] initWithCapacity:100];
} } // Called when the parser encounters an end element
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
NSLog (@”didEndElement”);
// Check to see which element we have ended
// We ended a Result element
if ([elementName isEqualToString:@”Result”]) { NSLog (@”capturedCharacters: %@” , capturedCharacters);
self.extractedTermsTextView.text = [self.extractedTermsTextView.text stringByAppendingFormat:@”%@\n”,capturedCharacters];
// Release the capturedCharacters instance variable [capturedCharacters release];
capturedCharacters = nil;
} } // Called when the parser finds characters contained within an element
Trang 4342 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (capturedCharacters != nil) {
[capturedCharacters appendString:string];
}
}
TermExtractViewController.m
Because you are only interested in Result elements, this code is straightforward If you encounter
the start of a Result element, you initialize your capturedCharacters instance variable in the
didStartElement method In didEndElement , you check to see that you ended a Result element
Then, you append the capturedCharacters string to the extractedTermsTextView
Finishing Up
The application is now complete You should be able to successfully build and run the program
When you tap the Extract Terms button, you will send the query to the web service If you have
an active Internet connection, and you have properly confi gured your own appid , you should
receive an XML result set back that contains the extracted terms You can verify this in the console
log The code will take the text contained in each Result element, parse it, and append it to the
extractedTermsTextView in the user interface Feel free to paste in any block of text that you
fi nd interesting to see what the Yahoo! service feels are the most signifi cant words or phrases in the
document
MOVING FORWARD
In this chapter, you learned about the basics of XML web services Then you learned how to call
XML web services using both the HTTP GET and POST methods This will enable you to call any
web service available on the Internet
You also learned how to use the Core Location framework to access the GPS functionality and
determine a device ’ s location Then, you learned how to use the MapKit framework to display and
annotate maps
Over the course of this entire book, you have explored the full spectrum of dealing with data on
the iPhone and iPad You learned how to display data on the device, extract data from enterprise
systems and store it on the device, use Core Data to generate and manage data on the device, and
use web services to communicate from your application to other services
You now have all of the tools necessary to build robust, data - driven applications I hope that you
fi nd the exploration of the frameworks and functionality available in the iPhone SDK helpful in your
daily work I hope that you take this knowledge, go out, and build amazing applications, because
the iPhone and iPad are amazing platforms for your software We are still only at the beginning
for these devices As these technologies evolve, the capabilities of the devices will only get better,
allowing you to build applications that are even more amazing!
Trang 5Tools for Troubleshooting
Your Applications
In this book, I have covered various topics related to building data - centric iPhone and iPad applications Because most readers are already familiar with iOS software development, this book does not include in - depth coverage of the tools that experienced developers may already know about such as Instruments and the Static Analyzer
This appendix covers these tools, which can be invaluable when troubleshooting your applications The techniques that you learn in this appendix are general You should be able
to use these techniques as - is with the current version of Instruments, and apply the same principles to future versions of the tool If you already know about these tools, perhaps you will learn a new tip or trick If you have never used these tools, you will learn how to use them
to effectively track down problems in your code
INSTRUMENTS
Instruments is a graphical tool that helps you to gather information about your application at runtime You can then use this information to help track down diffi cult bugs such as memory leaks Instruments is also valuable in profi ling the performance
of your application and helping you to track down and fi x bottlenecks Many different tools are available in the Instruments application to help you to troubleshoot a variety
of application problems
The Instruments application consists of a set of instruments that you use to collect data about your application as it runs You can see all of the instruments that are available
A
Trang 6344 ❘ APPENDIX A TOOLS FOR TROUBLESHOOTING YOUR APPLICATIONS
for use in Figure A - 1 The instruments
generally display their results graphically
You can have many instruments running
concurrently with their resulting graphs
displayed together in the application
interface This can help you analyze the
relationships between the data collected by
different instruments
You can also create custom instruments
that use DTrace to examine the execution
of your application DTrace is a dynamic
scripting tool that Sun created and Apple
ported to OS X
You cannot use DTrace custom instruments
on the iPhone OS directly, but you can use
them in conjunction with the simulator
when running your application on your development machine While this reduces the usefulness of
custom instruments because you cannot use them for performance profi ling on the device, you can
still build instruments to help you to debug your applications in the simulator
Because DTrace instruments are of limited usefulness to iPhone developers, I will not cover them
in detail You can refer to the Instruments user guide located at http://developer.apple.com/
iphone/library/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide for
more details on creating custom instruments using DTrace
Starting Instruments
You can start the Instruments tool by launching the application, which is located, by default, in
/YourDriveName/Developer/Applications or by selecting Run ➪ Run With Performance Tool
from the menu bar in Xcode
If you start the application directly, you will see a list of templates for the trace document that you
are about to start The trace document holds the set of all of your individual trace runs You can
save your trace documents so that you can review all of the data collected from your traces at any
time If you start Instruments from within Xcode, you are effectively selecting the template that you
will use when you choose an option under Instruments in the menu bar
The templates consist of default sets of instruments designed to assist you with specifi c tasks For
instance, you would select the Leaks template if you were interested in troubleshooting memory
leaks in your application After you select the Leaks template, the Instruments application appears
with both the Leaks and ObjectAlloc instruments loaded into the trace document If you examine
the defi nitions of each tool, you will see that you often want to use the ObjectAlloc instrument in
conjunction with the Leaks instrument because ObjectAlloc can give you insight into the history of
an object that the Leaks tool reports as a leak
FIGURE A - 1: Available instruments
Trang 7The Trace Document
The trace document is the group of tools that you are using, along with any test runs You can see
an example of a trace document in Figure A - 2
Detail Pane
Extended Detail Pane Track Pane
Instruments Pane
FIGURE A - 2: The trace document
The Instruments pane shows the list of instruments that you are using for the current trace Clicking the info button for an instrument displays that instrument ’ s confi guration options You can add instruments to the Instruments pane by dragging them from the instruments library (displayed with Command+L) and dropping them into the Instruments pane
The Track pane displays the graphical output of the instrument in a timeline Each instrument records its data into its own track The Track pane shows the time that an event occurred during the test run You can adjust the time scale using the slider at the bottom of the Instruments pane You can scroll the Track pane using the scrollbar at the bottom of the pane
The small triangle that appears at the top of the Track pane is the playhead The playhead indicates
the current time of the test run You can move the playhead to review the state of your application
at any given time during its execution You can add a fl ag at the current location of the playhead by clicking the fl ag icon with the plus sign next to it in the toolbar You can navigate forward to the
Trang 8346 ❘ APPENDIX A TOOLS FOR TROUBLESHOOTING YOUR APPLICATIONS
next fl ag or back to the previous fl ag by clicking the fl ag icons to the right or the left of the add fl ag
icon respectively
The Detail pane shows the details of the currently selected tool The Detail pane shows different
details based on the tool that you have selected in the Instruments pane You can select an item
in the Detail pane to view more detail about the item in the Extended Detail pane The Extended
Detail pane is particularly useful because it shows a stack trace for the method call that you have
selected in the Detail pane
I fi nd it useful to display the fi le icons in the Extended Detail pane because doing so makes the
calls in the stack that originated in your code obvious You can enable the fi le icons by clicking on
the gear icon in the Extended Details pane If you double - click on an item in the call stack that
corresponds to one of your source code fi les, Instruments will display the source code in the Detail
pane Instruments highlights the line of code that was executing when the sample was taken
You can narrow the amount of data contained in the Detail pane by specifying an inspection range
To specify an inspection range, move the playhead to the location in the timeline where you want
the range to begin and click on the left icon in the Inspection Range icon group in the toolbar
Next, move the playhead to the location in the timeline where you want the range to end and click
on the right icon in the Inspection Range icon group in the toolbar You should see the data in the
Detail pane reduce down to include only the data collected during the time window specifi ed by
the inspection range that you have created
Objective - C Memory Management
In the upcoming section, you will explore the use of Instruments to discover the cause of a memory
leak First, let ’ s take a brief detour to make sure that you understand how memory management
works in Objective - C
Although garbage collection is a nice feature available to developers on the Mac platform, there is
currently no garbage - collected version of the Objective - C runtime available for the iPhone or iPad
Therefore, you are responsible for managing the memory consumed by the objects that you create
in your applications If you fail to properly free the memory that you allocate, the total amount of
memory consumed by your application will grow as the application runs This failure to clean up
unused memory results in a memory leak Eventually, if your program consumes too much memory,
the OS will terminate your application
All Objective - C classes that inherit from NSObject have a retain count When an object is allocated
using alloc or new , its retain count is set to 1 The retain count is a counter that indicates the
number of bits of code that are interested in the object When you need to hold on to a reference
to an object, you increment the retain count by calling the retain method on the object When
you are fi nished with an object, you call release to decrement the retain count The retain count
determines when the object should be de - allocated and its dealloc method called
You need to be careful to balance calls to new , alloc , or retain with calls to release If you
have too few calls to release , the retain count for the object will never drop to 0 and the object
will never be released, resulting in a memory leak If you call release too many times, you will
over - release the object, causing a segmentation fault and an application crash
Trang 9In general, adding an object to a collection such as NSMutableArray increments the retain count
Likewise, removing an object from a collection decrements the retain count Simply obtaining
an object from a collection typically returns an autoreleased object If you need to hold on to the reference to an autoreleased object, you need to call retain on it
You can also send the message autorelease to an object This indicates that the runtime should release the object at a point in the future, but not right away You use autorelease pools to keep track of all autoreleased objects There is an application - wide autorelease pool that the project template creates automatically when you begin your application You can create local pools yourself as well
Autorelease is particularly useful for returning objects from methods You can allocate the object that you plan to return from the method, confi gure it, and then autorelease it It is then the caller ’ s responsibility to retain the object to ensure that it has the proper retain count The Objective - C runtime will send an autoreleased object to the release message one time for every time you call
autorelease on it when the autorelease pool is drained or de - allocated
When you create an object with a helper method that has alloc , new , or copy in its name, it is your responsibility to release it Objects created in this way, by convention, have a retain count of 1 If you use a method that returns an object such as stringWithString to get an instance of an object, you should assume that the object is autoreleased
If you need to hold on to a reference to an autoreleased object, it is your responsibility to call retain The default autorelease pool will de - allocate autoreleased objects each time through the application ’ s run loop So, if you get an autoreleased object in a function, use it right away, and don ’ t need it after the method call is complete, you do not need to worry about retaining it However, if you plan to put
an autoreleased object into an instance variable for access at a later time, you have to call retain
on it or else it will be de - allocated at the end of the run loop and your application will crash with a segmentation fault when you try to send a message to the de - allocated object
You should use release instead of autorelease whenever possible as there is less overhead in calling release If you are going to be creating and autoreleasing many objects, in a loop perhaps, you should wrap the loop in its own autorelease pool
You can send the retainCount message to any NSObject to obtain the current retain count of that object You generally won ’ t use this method in a production application, but it can be helpful to log the retain count of an object as you are trying to debug memory problems
The rules of memory management are simple To summarize:
If you create an object with alloc , new , or copy , the object will have a retain count of 1 and you are responsible calling release
If you get a reference to an object in any other way, you can assume that it has a retain count of 1 and has been autoreleased If you need to hold on to a reference to the object,
retain it
If you call retain on an object, you have to balance the call to retain with a call to
release
A memory leak occurs when you lose the reference to a pointer for an object that you have not
➤
➤
➤
Trang 10348 ❘ APPENDIX A TOOLS FOR TROUBLESHOOTING YOUR APPLICATIONS
to the number of calls to release This is called over - retaining an object
Over - retaining will result in the object ’ s retain count never reaching 0
at which time the runtime frees the memory consumed by the object
Because the object is not freed, you have leaked the memory consumed
by the object for the remainder of the life of the program
Sample Memory Leak Application
Now that you have an understanding of memory management and
Objective - C, you will build an application with a memory leak and then
use Instruments to fi nd and fi x that leak The application will be very
simple with only a single button for the user interface, as you can see in
Figure A - 3 When you tap the Go button, a routine with a memory leak
will run and log to the console
Start a new View - based Application project for iPhone called
MemoryLeaker Open the MemoryLeakerViewController.h header fi le
and add an action for the Go button as follows:
#import < UIKit/UIKit.h >
@interface MemoryLeakerViewController : UIViewController {
}
-(IBAction) goPressed:(id) sender;
@end
Now, you need to build the interface in Interface Builder Open the MemoryLeakerViewController
.xib fi le in Interface Builder Add a UIButton to the View and wire the TouchUpInside event to
File ’ s Owner goPressed method Save the XIB fi le and close Interface Builder
Next, you are going to implement the goPressed method in the MemoryLeakerViewController.m
implementation fi le Remember that this code has a memory leak so don ’ t use it in any of your
applications Here is the implementation of the goPressed method:
-(IBAction) goPressed:(id) sender
{
NSMutableString *theString = [[NSMutableString alloc] init];
[theString appendString:@”This”] ;
[theString appendString:@” is”] ;
[theString appendString:@” a”] ;
[theString appendString:@” string”] ;
NSLog(@”theString is: %@”, theString);
}
FIGURE A - 3:
MemoryLeaker application