Phát triển ứng dụng cho iPhone và iPad - part 38 ppsx

10 227 0
Phát triển ứng dụng cho iPhone và iPad - part 38 ppsx

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

Thông tin tài liệu

NSLog (@”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 Example 2: Term Extraction ❘ 339 CH011.indd 339CH011.indd 339 9/18/10 10:05:17 AM9/18/10 10:05:17 AM 340 ❘ 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”); } CH011.indd 340CH011.indd 340 9/18/10 10:05:17 AM9/18/10 10:05:17 AM // 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 Example 2: Term Extraction ❘ 341 CH011.indd 341CH011.indd 341 9/18/10 10:05:18 AM9/18/10 10:05:18 AM 342 ❘ 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! CH011.indd 342CH011.indd 342 9/18/10 10:05:18 AM9/18/10 10:05:18 AM Tools 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 APP-A.indd 343APP-A.indd 343 9/17/10 7:24:02 PM9/17/10 7:24:02 PM 344 ❘ 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 APP-A.indd 344APP-A.indd 344 9/17/10 7:24:06 PM9/17/10 7:24:06 PM Instruments ❘ 345 The 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 PaneTrack 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 APP-A.indd 345APP-A.indd 345 9/17/10 7:24:07 PM9/17/10 7:24:07 PM 346 ❘ 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. APP-A.indd 346APP-A.indd 346 9/17/10 7:24:08 PM9/17/10 7:24:08 PM Instruments ❘ 347 In 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 deleted from the heap, or if you do not match the number of calls to retain , alloc , new , or copy ➤ ➤ ➤ APP-A.indd 347APP-A.indd 347 9/17/10 7:24:08 PM9/17/10 7:24:08 PM 348 ❘ 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 APP-A.indd 348APP-A.indd 348 9/17/10 7:24:09 PM9/17/10 7:24:09 PM . 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. that are available A APP-A.indd 343APP-A.indd 343 9/17/10 7:24:02 PM9/17/10 7:24:02 PM 344 ❘ APPENDIX A TOOLS FOR TROUBLESHOOTING YOUR APPLICATIONS for use in Figure A - 1. The instruments generally. the history of an object that the Leaks tool reports as a leak. FIGURE A - 1: Available instruments APP-A.indd 344APP-A.indd 344 9/17/10 7:24:06 PM9/17/10 7:24:06 PM Instruments ❘ 345 The

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

Tài liệu cùng người dùng

Tài liệu liên quan