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

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

10 206 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 10
Dung lượng 3,22 MB

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

Nội dung

Finally, add an instance method called parseXML that you will invoke to start the XML processing: - IBAction extractTerms:idsender; - void parseXML; The complete header should look lik

Trang 1

Next, you defi ne an MKCoordinateRegion struct You will pass this struct to the mapView to defi ne the region that you want to display An MKCoordinateRegion consists of a span and a center point

You will center the map on the coordinate that you receive from Core Location

Next, you tell the mapView to set the region displayed on the map and to animate the transition to your new region Finally, you tell the Core Location manager to stop getting location updates from the GPS Because your application does not need extremely accurate resolution, nor do you need constant updates from the GPS, you can conserve power by turning the GPS off

For the next step, you need to make a couple of additions to the viewDidLoad method Because you will be customizing the pin colors for your annotations, you need to set the mapView delegate

to self In addition, for illustrative purposes, you will display the user ’ s location on the map by setting the map view ’ s showsUserLocation property to YES When using the showsUserLocation property, you need to be aware that this will cause the map view to use Core Location to

retrieve and maintain the user ’ s location on the map This forces the GPS receiver to remain on, consuming valuable battery power You should carefully consider if your application needs this functionality or not before using it This example uses this feature to demonstrate a capability

of the map view to display the user ’ s current location Here is the complete implementation of viewDidLoad :

- (void)viewDidLoad { [super viewDidLoad];

// Create the results array self.results = [[NSMutableArray alloc] init];

// Create the Core Location CLLocationManager CLLocationManager *locationManager = [[CLLocationManager alloc] init];

// Set the delegate to self [locationManager setDelegate:self];

// Tell the location manager to start updating the location [locationManager startUpdatingLocation];

// Set the delegate for the searchbar [self.searchBar setDelegate:self];

// Set the delegate for the mapView [self.mapView setDelegate:self];

// Use Core Location to find the user’s location and display it on the map // Be careful when using this because it causes the mapview to continue to // use Core Location to keep the user’s position on the map up to date self.mapView.showsUserLocation = YES;

}

LocationSearchViewController.m

Trang 2

330 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES

When the user clears the text from the search bar, you want to clear the old annotations from the

map You can do this by implementing the searchBar:textDidChange: delegate method like this:

// Called when the searchbar text changes

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText{

NSLog (@”textDidChange”);

// If the text was cleared, clear the map annotations

if ([searchText isEqualToString:@””])

{

// Clear the annotations

[self.mapView removeAnnotations:self.mapView.annotations];

// Clear the results array

[self.results removeAllObjects];

}

}

LocationSearchViewController.m

You implement this code to check to see if the user has cleared the search string If he has, you

remove the annotations from the map and clear your results array

In the last bit of code, you will implement the mapView:viewForAnnotation: delegate method

The map view will call this method when the map needs the view for an annotation If you wanted

to implement a custom view for your annotations, you would do it in this method Instead of

implementing a custom view, you will use the MKPinAnnotationView ; however, you could easily

replace this with your own view You will change the color of the pin based on the user rating of the

business that you are plotting on the map Here is the code:

- (MKAnnotationView *)mapView:(MKMapView *)mapView

viewForAnnotation:(id < MKAnnotation > )annotation

{

// If we are displaying the user’s location, return nil

// to use the default view

if ([annotation isKindOfClass:[MKUserLocation class]]) {

return nil;

}

// Try to dequeue an existing pin

MKPinAnnotationView *pinAnnotationView =

(MKPinAnnotationView *)

[self.mapView dequeueReusableAnnotationViewWithIdentifier:@”location”];

if (!pinAnnotationView) {

// We could not get a pin from the queue

pinAnnotationView=[[[MKPinAnnotationView alloc]

initWithAnnotation:annotation

Trang 3

reuseIdentifier:@”location”] autorelease];

pinAnnotationView.animatesDrop=TRUE;

pinAnnotationView.canShowCallout = YES;

} // We need to get the rating from the annotation object // to color the pin based on rating

Result *resultAnnotation = (Result*) annotation;

if (resultAnnotation.rating > 4.5) { pinAnnotationView.pinColor = MKPinAnnotationColorGreen;

} else if (resultAnnotation.rating > 3.5) { pinAnnotationView.pinColor = MKPinAnnotationColorPurple;

} else { pinAnnotationView.pinColor = MKPinAnnotationColorRed;

} return pinAnnotationView;

}

LocationSearchViewController.m

The fi rst line of the method checks to see if the annotation is for the user location view If it is, you simply return nil to tell the map to use the default annotation

Next, you will see the attempt to dequeue an existing annotation view The MapView works very much like the TableView in this respect It doesn ’ t make sense to keep invisible map annotations

in memory Therefore, the MapView creates and releases annotations as they become visible or disappear from the map respectively Instead of creating new annotation instances every time, the MapView maintains an internal queue of annotation objects that it can reuse Therefore, you fi rst try to dequeue an annotation If you cannot, you create a new pin annotation view with the correct reuse identifi er Then, you set the attributes of this view

Next, you cast the annotation that the MapView is asking for to a Result object Then, you use the rating property of the Result to set the color of the pin Finally, you return the pinAnnotationView

Finishing Up

The code is now complete You should be able to successfully build and run the application If you attempt to run the application in the simulator, you will see that the device thinks that it is at Apple headquarters, regardless of where you are actually located This is by design Enter a search term

in the search bar and watch the pins drop to show you the results You can view the XML returned

by the web service in the console

Trang 4

332 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES

EXAMPLE 2: TERM EXTRACTION

When making calls to a web service, you will often use the HTTP GET

method to send parameters to the service When dealing with REST

based web services, you use GET to indicate that you are performing a

query for some data from the server There are occasions where you will

need to POST data to the server Many SOAP - based web services use

POST to send data REST uses the POST method to indicate that you are

sending data to the server and intend to modify the database

Sending a POST request is very similar to sending a GET request with some

minor exceptions, as you will see in the example code

In this example, you will make a call to the Yahoo! Term Extraction

service This service returns a list of what it deems to be the signifi cant

words and phrases in the text passage that you submit There is no

defi nition of what Yahoo! determines to be “ signifi cant, ” nor is their

algorithm to determine signifi cance public Because of the length of the

string that you can submit to the service, it is not practical to use the GET

method; therefore, the service requires that you use POST to send your

string into the web service You can apply the same principles that you

use here to any web service that requires you to submit data using the

POST method The completed example will look like Figure 11 - 5

Getting Started

To get started, open Xcode and create a new View - based application called TermExtract In the

TermExtractViewController.h header fi le, add instance variables for two UITextView variables:

UITextView *textToExtractTextView;

UITextView *extractedTermsTextView;

Next, add properties for these UITextView s:

@property (nonatomic, retain) IBOutlet UITextView *textToExtractTextView;

@property (nonatomic, retain) IBOutlet UITextView *extractedTermsTextView;

Also, add instance variables for the response data that you will receive from the server in response

to your request, and the characters that you will capture during XML parsing:

NSMutableData *responseData;

NSMutableString *capturedCharacters;

Now, add a property for the responseData :

@property (nonatomic, retain) NSMutableData *responseData;

FIGURE 11 - 5: Complete term extraction application

Trang 5

Next, add an IBAction method called extractTerms that you will call after the user enters the text

to send to the service Finally, add an instance method called parseXML that you will invoke to start the XML processing:

- (IBAction) extractTerms:(id)sender;

- (void) parseXML;

The complete header should look like this:

#import < UIKit/UIKit.h >

@interface TermExtractViewController : UIViewController { UITextView *textToExtractTextView;

UITextView *extractedTermsTextView;

NSMutableData *responseData;

NSMutableString *capturedCharacters;

}

@property (nonatomic, retain) IBOutlet UITextView *textToExtractTextView;

@property (nonatomic, retain) IBOutlet UITextView *extractedTermsTextView;

@property (nonatomic, retain) NSMutableData *responseData;

- (IBAction) extractTerms:(id)sender;

- (void) parseXML;

@end

TermExtractViewController.h

In the implementation fi le, synthesize the textToExtractTextView,extractedTermsTextView, responseData properties:

@synthesize textToExtractTextView,extractedTermsTextView,responseData;

Then, add the code to clean up the properties in the viewDidUnload method:

- (void)viewDidUnload { // Release any retained subviews of the main view.

// e.g self.myOutlet = nil;

self.textToExtractTextView=nil;

self.extractedTermsTextView=nil;

self.responseData=nil;

}

TermExtractViewController.m

Trang 6

334 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES

Finally, release your instance variables and call the superclass ’ s dealloc method in dealloc :

- (void)dealloc {

[textToExtractTextView release];

[extractedTermsTextView release];

[responseData release];

[super dealloc];

}

TermExtractViewController.m

Building the User Interface

You will now build the user interface for the

application using Interface Builder Double - click on

the TermExtractViewController.xib fi le in Xcode to open the

fi le in Interface Builder Once the interface view is open, add

two UITextView s, two UILabel s, and a UIButton , as shown

in Figure 11 - 6

Change the title attribute of the UIButton to read “ Extract

Terms ” Change the text of the top UILabel to read “ Text to

extract: ” and the bottom UILabel to “ Extracted Terms: ”

As default text in the “ Text to extract: ” TextView, I set the text

to the Declaration of Independence I have included a text fi le

containing the declaration, or you could use your own text or

just provide text at runtime Delete the default text from the

extracted terms TextView

Next, you need to hook up the TextViews to the proper

outlets in Interface Builder Hook up the Extract Terms

button to the IBAction extractTerms in File ’ s Owner In the

TermExtractViewController.m implementation fi le, implement

a stub extractTerms method to log when someone calls the

method You will use this to verify that you have correctly wired up the button in Interface Builder

Here is the stub code:

- (IBAction) extractTerms:(id)sender

{

NSLog (@”extractTerms”);

}

Build and run the application Click the extractTerms button and verify that you see the log

message in the console This shows that you have correctly wired the button to the method If you

do not see the message in the console, make sure that you have properly wired the button to the

message in Interface Builder

FIGURE 11 - 6: Term extract user interface

Trang 7

You are fi nished with the user interface, so you can close Interface Builder

Implementing the POST Call

You will implement the extractTerms method to POST the request to the web service

The fi rst thing that you do in this method is to dismiss the keyboard by calling the resignFirstResponder method on the TextView Next, you clear the list of extracted terms

to eliminate old results:

- (IBAction) extractTerms:(id)sender {

NSLog (@”extractTerms”);

// Hide the keyboard [self.textToExtractTextView resignFirstResponder];

// Clear the old extracted terms self.extractedTermsTextView.text = @””;

TermExtractViewController.m

Now, you create a string to hold the URL that you plan to call This is the address of the Yahoo!

Term Extraction web service Next, you create an NSURL object with this string:

// Create a string for the URL NSString *urlString = @”http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction”;

// Create the NSURL NSURL *url = [NSURL URLWithString:urlString];

TermExtractViewController.m

The next line is where using the POST method differs from using GET If you recall, when using the GET method, you simply set the URL string, set the parameter values inline, and sent the request off through the NSURLConnection When using the POST method, you need to do things a little differently After you create the NSURLRequest , you will need to modify some of its properties

Therefore, you must use an NSMutableURLRequest instead:

// Create a mutable request because we will append data to it.

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy

timeoutInterval: 30.0];

TermExtractViewController.m

Trang 8

336 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES

The fi rst change that you will make to the request is to set the HTTP method that you plan to use

Remember that you are using the POST method The default method is GET , so you have to change

this in the request to POST using the setHTTPMethod method:

// Set the HTTP method of the request to POST

[request setHTTPMethod:@”POST”];

TermExtractViewController.m

Next, you will build a string to hold your parameters In this example, there is only one parameter,

but many parameters can optionally be passed using the POST method You should note that

parameters must be passed using the HTML parameter passing syntax name=value just like

when using the GET method In your implementation, make sure that you replace the appid with

the actual appid that you receive from Yahoo! after you register your application Here is your

parameter string:

// Build a string for the parameters

NSString *parameters = [[NSString alloc] initWithFormat:

@”appid=YOUR_ID_GOES_HERE & context=%@”,

self.textToExtractTextView.text];

TermExtractViewController.m

When you use the GET method to call a web service, you pass the parameters in the query string

of the HTTP request However, when you use POST , you pass those parameters in the body of the

HTTP message Therefore, you have to set the HTTP body using the setHTTPBody method:

// Set the body of the request

[request setHTTPBody:[parameters dataUsingEncoding:NSUTF8StringEncoding]];

TermExtractViewController.m

The rest of the code for the method is the same as you have seen before First, you create the

NSURLConnection :

NSURLConnection *connection =

[[NSURLConnection alloc] initWithRequest:request delegate:self];

TermExtractViewController.m

Next, you instantiate your responseData property:

// Make sure that the connection is good

if (connection) {

// Instantiate the responseData data structure to store to response

self.responseData = [NSMutableData data];

}

Trang 9

else { NSLog (@”The connection failed”);

}

TermExtractViewController.m

Finally, you need to clean up your local variables:

// Clean up our local variables [urlString release];

[parameters release];

TermExtractViewController.m

Here is the complete method implementation:

- (IBAction) extractTerms:(id)sender {

NSLog (@”extractTerms”);

// Hide the keyboard [self.textToExtractTextView resignFirstResponder];

// Clear the old extracted terms self.extractedTermsTextView.text = @””;

// Create a string for the URL NSString *urlString =

@”http://search.yahooapis.com/ContentAnalysisService/V1/termExtraction”;

// Create the NSURL NSURL *url = [NSURL URLWithString:urlString];

// Create a mutable request because we will append data to it.

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy

timeoutInterval: 30.0];

// Set the HTTP method of the request to POST [request setHTTPMethod:@”POST”];

// Build a string for the parameters NSString *parameters = [[NSString alloc] initWithFormat:

@”appid=YOUR_ID_GOES_HERE & context=%@”, self.textToExtractTextView.text];

// Set the body of the request [request setHTTPBody:[parameters dataUsingEncoding:NSUTF8StringEncoding]];

// Create the connection and send the request

Trang 10

338 ❘ CHAPTER 11 INTEGRATING WITH WEB SERVICES

NSURLConnection *connection =

[[NSURLConnection alloc] initWithRequest:request delegate:self];

// Make sure that the connection is good

if (connection) {

// Instantiate the responseData data structure to store to response

self.responseData = [NSMutableData data];

}

else {

NSLog (@”The connection failed”);

}

// Clean up our local variables

[urlString release];

[parameters release];

}

TermExtractViewController.m

Receiving the XML Response

In order to receive the response from the web service, you need to implement the NSURLConnection

delegate methods as you did in the previous example

First, you will implement the connection:didReceiveResponse: method This delegate method is

called when the NSURLConnection creates the response The connection could call this method

multiple times, so you need to reset your response data by setting its length to zero each time this

method runs Here is the implementation:

// Called when the connection has enough data to create an NSURLResponse

- (void)connection:(NSURLConnection *)connection

didReceiveResponse:(NSURLResponse *)response {

NSLog (@”connection:didReceiveResponse:”);

NSLog(@”expectedContentLength: %qi”, [response expectedContentLength] );

NSLog(@”textEncodingName: %@”, [response textEncodingName]);

[self.responseData setLength:0];

}

TermExtractViewController.m

Next, you need to implement the connection:didReceiveData: delegate method The connection

calls this method each time it receives data so you need to append the received data to your

responseData buffer:

// Called each time the connection receives a chunk of data

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data

{

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

TỪ KHÓA LIÊN QUAN