Reading JSON from URL and adding MKAnnotations - iphone

I've been through several different tutorials trying to get this working, but they seem to gloss over some crucial steps that a beginner might not know.
I have a JSON file at a URL with name, latitude, and longitude listed. How can I import that to an array or dictionary (I don't know the difference), and then iterate over it and create a new annotation with each iteration.
IOS6, Storyboards
_ Added Code _
ViewController.h
#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#interface ViewController : UIViewController {}
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, strong) NSMutableData *downloadData;
#end
ViewController.m
#import "ViewController.h"
#import "MapViewAnnotation.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_downloadData = [NSMutableData new];
NSURL *requestURL = [NSURL URLWithString:#"OMITTED/apptest/locations.json"];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_downloadData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
id parsed = [NSJSONSerialization JSONObjectWithData:_downloadData options:kNilOptions error:nil];
for (NSDictionary *pointInfo in parsed)
{
NSLog([parsed objectForKey:#"name"]);
double xCoord = [(NSNumber*)[parsed objectForKey:#"lat"] doubleValue];
double yCoord = [(NSNumber*)[parsed objectForKey:#"lon"] doubleValue];
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(xCoord, yCoord);
MKPointAnnotation *point = [MKPointAnnotation new];
point.coordinate = coords;
point.title = [parsed objectForKey:#"name"];
[self.mapView addAnnotation:point]; // or whatever your map view's variable name is
}
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)viewDidUnload {
[super viewDidUnload];
// ARC Problem --- [_mapView release];
self.mapView = nil;
}
#end

With iOS 5 there's a JSONSerializer class that can convert the raw JSON data from your URL into an array or dictionary as appropriate.
You'll need to download the data from the server:
NSURL *requestURL = [NSURL URLWithString:#"<your url here>"];
NSURLRequest *request = [NSURLRequest requestWithURL:requestURL];
NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
[connection start];
Then you'll add these delegate methods:
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[_downloadData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
id parsed = [NSJSONSerialization JSONObjectWithData:_downloadData options:kNilOptions error:nil];
}
_downloadData is an instance variable or property of your class of type NSMutableData.
That parsed variable will contain your data from the server. It's probably an array if it's a list of points, so you can iterate through it using fast enumeration:
for (NSDictionary *pointInfo in parsed) {
double xCoord = [(NSNumber*)[parsed objectForKey:#"<key for lat coord>"] doubleValue];
double yCoord = [(NSNumber*)[parsed objectForKey:#"<key for long coord>"] doubleValue];
CLLocationCoordinate2D coords = CLLocationCoordinate2DMake(xCoord, yCoord);
MKPointAnnotation *point = [[MKPointAnnotation new] autorelease];
point.coordinate = coords;
point.title = [parsed objectForKey:#"<key for title>"];
[self.mapView addAnnotation:point]; // or whatever your map view's variable name is
}

I have an open source project on GitHub that uses the serializer with the NSCoding protocol so you can automatically create instances right from the JSON stream.
It's here.

Related

NSURLConnection very long downloading

I'm facing problem with downloading 5 MB file, it taking more then 2 minutes on iPhone 5 with iOS 6.1.
Using iPhone 4S with same iOS version it taking only 10 seconds, both are using WiFi.
I have tried different cache Policy and timeout Interval of NSURLRequest, it changed nothing, it's still taking long time. Download is over HTTP.
I'm using NSURLConnection class, before downloading this "big" file I'm downloading two others.
Don't know what else can be important,to reduce the time.
Thanks in advance.
Code:
#interface MyClass : NSObject <NSURLConnectionDelegate>
{
#private id delegate;
NSURLConnection *connection;
NSMutableData* responseData;
//...
}
#import "MyClass.h"
#implementation MyClass
-(void)getObj1:(id)delegateObj
{
delegate = delegateObj;
NSString *url = #"...";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(connection)
{
responseData = [NSMutableData data];
}
}
-(void)getObj2:(*String)somesString
{
NSString *url = #"...";
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if(connection)
{
responseData = [NSMutableData data];
}
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
//....
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if(firstRequest)
{
//save data from first request and set responseData clear
[self getObj2:#"..."];
}
}
and others without anything special, I hope this will be enough
I have found this post https://devforums.apple.com/message/754875#754875 but still doesn't work fine for me. However now I better understand this strange situation.
Use AFDownloadRequestOperation (AFNetworking "sublass") - you can have also pause/resume operation.
Here you have an example https://stackoverflow.com/a/12209618
You used GCD dispatch_async queue to execute set of NSURLRequest request to download data from server or getting server response.
NSString *webURL = #"http://therealurl.appspot.com/?format=json&url=bit.ly/a";
NSURL *url = [NSURL URLWithString:webURL];
NSURLRequest *awesomeRequest = [NSURLRequest requestWithURL:url];
NSURLConnection *connection=[[NSURLConnection alloc] initWithRequest:awesomeRequest delegate:self];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
dispatch_async(queue, ^{
NSRunLoop *loop=[NSRunLoop currentRunLoop];
[connection scheduleInRunLoop:loop forMode:NSRunLoopCommonModes];
//[self processTheAwesomeness];
});
Well in my experience AFNetworking does an awsome job in handling the downloads.I am using a downloading operation on files with 10+ MB size .So I strongly suggest using it.
My answer on stack to show progressbar.See the answer where i implement both the ways ,with AFNetworking and NSUrlconnection.You can try both ways and can see the progress and you can calculate how the bytes get downloaded in each packet.By tracking it so you can analyse how it varies in the download time.
Try it
I'd propose a solution where you have some kind of a communication manager which has an NSOperationQueue it handles, with a single entry point method where you give it a the URL where the content lives you want to download and a success and a failure block.
The communication manager than creates an NSOperation where you create the NSURLRequest and handle the callbacks.
As soon as the commninication manager puts the operation onto the queue its start method is called.
In my communication manager implementation I keep track (besides putting the operations onto the queue) of every started operation via an NSMutableDictionary so that you can cancel a single or all operations (In the sample code provided the operationKey is used for this purpose. Here the JSONOperation returns (in case of success) an NSString to the communicator but it could be any kind of data too, e.g. I use the same class for downloading images, so I'd pass back the data object itself.
Below you can find my JSONOperation class as an example. I you like the idea I could put the other files on Gist.
My NSOperation looks like this
#interface JSONOperation : NSOperation <NSURLConnectionDataDelegate, OperationDelegate>
+ (instancetype)jsonOperationForProvider:(id)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure;
#end
#import "JSONOperation.h"
#import "ProviderDelegate.h"
#interface JSONOperation()
#property (nonatomic, assign) BOOL executing;
#property (nonatomic, assign) BOOL finished;
#property (nonatomic, assign) BOOL cancelled;
#property (nonatomic, strong) NSURL *url;
#property (nonatomic, weak) id <ProviderDelegate> delegate;
#property (nonatomic, strong) NSURLConnection *connection;
#property (nonatomic, strong) NSMutableData *receivedData;
#property (nonatomic, copy) OperationFailure failure;
#property (nonatomic, copy) OperationSuccessWithString success;
#end
#implementation JSONOperation
- (void)start
{
if ([self isCancelled])
{
[self willChangeValueForKey:#"isFinished"];
_finished = YES;
[self didChangeValueForKey:#"isFinished"];
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:self.url];
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
[self.connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
[self.connection start];
[self willChangeValueForKey:#"isExecuting"];
_executing = YES;
[self didChangeValueForKey:#"isExecuting"];
}
- (NSMutableData *)receivedData
{
if (nil == _receivedData) {
_receivedData = [NSMutableData data];
}
return _receivedData;
}
+ (instancetype)jsonOperationForProvider:(id <ProviderDelegate>)provider success:(OperationSuccessWithString)success failure:(OperationFailure)failure
{
NSAssert(nil != provider, #"provider parameter can't be nil");
JSONOperation *operation = [[[self class] alloc] init];
operation.delegate = provider;
operation.url = provider.contentURL;
operation.failure = failure;
operation.success = success;
return operation;
}
- (BOOL)isConcurrent {
return YES;
}
- (BOOL)isExecuting {
return _executing;
}
- (BOOL)isFinished {
return _finished;
}
- (BOOL)isCancelled {
return _cancelled;
}
#pragma mark - NSURLConnectionDataDelegate
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
if (_success) {
NSString *receivedText = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
_receivedData = nil;
self.success(self, receivedText);
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.receivedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
if (_failure) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.failure(self, error);
}];
}
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_executing = NO;
_finished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark - OperationDelegate
- (NSString *)operationKey
{
return [self.url absoluteString];
}
- (id)provider
{
return _delegate;
}
- (void)cancelOperation
{
_failure = nil;
_success = nil;
[self.connection cancel];
_connection = nil;
_receivedData = nil;
_url = nil;
[self willChangeValueForKey:#"isCancelled"];
[self willChangeValueForKey:#"isFinished"];
[self willChangeValueForKey:#"isExecuting"];
_executing = NO;
_finished = YES;
_cancelled = YES;
[self didChangeValueForKey:#"isCancelled"];
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#end
EDIT - Gist Sample files
Have you tried AFNetworking? It' s a wrapper on NSURLConnection. I'm not sure if it would help you in getting a faster download, but it sure does give you an edge over NSURLConnection.
Just try using gzip to compress the remote file for NSURLRequest. It'll speed up your connection dramatically.
To use this, you need to have it installed on the server, and the good news is if you're using apache2 on your server, it comes by default. To test to make sure your server/URL had gzip compression enabled, test it with this online tool:
http://www.feedthebot.com/tools/gzip/
If the answer is yes, proceed to add the code to your Objective-C code in Xcode. After this line in your code:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:120.0];
just add this:
// Create a mutable copy of the immutable request and add more headers
NSMutableURLRequest *mutableRequest = [request mutableCopy];
//add gzip compression
[mutableRequest addValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
// Now set our request variable with an (immutable) copy of the altered request
request = [mutableRequest copy];
This will speed up your response time noticeably, and you do not need to use AFNetworking for a small NSURLRequest or NSURLConnection task.
I'm not sure what your problem is, but the following code works reliably for me.
- (id)init
{
self.downloadQueue = [[NSOperationQueue alloc] init];
[self.downloadQueue setMaxConcurrentOperationCount:1];
}
- (void)doDownload:(NSURL *)url
{
[self.downloadQueue addOperation:[NSBlockOperation blockOperationWithBlock:^{
NSData *data =[NSData dataWithContentsOfURL:url];
dispatch_sync(dispatch_get_main_queue(), ^{
NSAutoreleasePool *mainQueuePool = [[NSAutoreleasePool alloc] init];
... update user interface ...
[mainQueuePool release];
});
}]];
}
I think it's a problem in your device. Try another device from a friend.

NSURLConnection and JSON Data

I am stuck with something crazy. I used ASIHTTPRequest to receive my data from a web service and everything worked fine. I switched to using a NSURLConnection and I am receiving the same data and parsing it the same way but my code won't recognize the data with the NSURLConnection.
Here is the data I am receiving (from NSLog)
Did receive data: {"d":"[{\"id\":1.0,\"Category\":1,\"hPlan\":0.0,\"Tip\":\"It takes 3500
calories to gain a pound. If you want to lose a pound per week, reduce your calorie
intake by 250 calories and incorporate daily physical activity that will burn 250
calories.\",\"TipDate\":\"2012-05-12T00:00:00\",\"TimeStamp\":\"AAAAAAAAB9I=\"}]"}
2012-06-06 09:42:11.809 StaticTable[27488:f803] Jsson Array: 0
2012-06-06 09:42:11.809 StaticTable[27488:f803] Jsson Array: (null)
Code:
#import "UYLFirstViewController.h"
#import "MBProgressHUD.h"
#import "JSON.h"
#interface UYLFirstViewController ()
#end
#implementation UYLFirstViewController
#pragma mark -
#pragma mark === UIViewController ===
#pragma mark -
#synthesize MessageField;
#synthesize jsonArray = _jsonArray;
#synthesize TipLabelField;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.title = NSLocalizedString(#"Tickle!", #"Tickle!");
self.tabBarItem.image = [UIImage imageNamed:#"heart_plus"];
[self GetTipOfDay];
}
return self;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
-(BOOL)GetTipOfDay{
NSDate *date = [NSDate date];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc]init];
[dateFormat setDateFormat:#"EEEE MMMM d, YYYY"];
NSString *dateString = [dateFormat stringFromDate:date];
NSString *yourOriginalString = #"Tip of the Day for ";
yourOriginalString = [yourOriginalString stringByAppendingString:dateString];
TipLabelField.text = yourOriginalString;
NSURL *url = [NSURL URLWithString:#"http://www.mysite.com/api/GetHealth.asmx/getTipOfDay"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
[request setHTTPMethod:#"GET"];
[request setValue:#"application/json" forHTTPHeaderField:#"Accept"];
[request setValue:#"application/json" forHTTPHeaderField:#"Content-Type"];
[NSURLConnection connectionWithRequest:request delegate:self];
// Clear text field
MessageField.text = #"";
// Start hud
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = #"Gathering Tip of the Day...";
return TRUE;
}
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[MBProgressHUD hideHUDForView:self.view animated:YES];
NSLog(#"Did receive data: %#", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
NSDictionary *responseDict = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] JSONValue];
NSString *jsonResponse = [responseDict objectForKey:#"d"];
self.jsonArray = [jsonResponse JSONValue];
NSLog(#"Jsson Array: %d", [jsonArray count]);
NSLog(#"Jsson Array: %#", jsonArray);
NSEnumerator *myEnumerator;
myEnumerator = [jsonArray objectEnumerator];
int i;
i=0;
id myObject;
while (myObject = [myEnumerator nextObject])
{
NSDictionary *itemAtIndex = (NSDictionary *)[self.jsonArray objectAtIndex:i];
NSLog(#"Checking for games");
NSString *myCheck = [itemAtIndex objectForKey:#"FName"];
if ([myCheck length] != 0)
{
// NSLog(myCheck);
MessageField.text = myCheck;
}
}
}
- (void)viewDidUnload {
[self setMessageField:nil];
[self setTipLabelField:nil];
[super viewDidUnload];
}
#end
#import <UIKit/UIKit.h>
#interface UYLFirstViewController : UIViewController{
NSMutableArray *jsonArray;
}
#property (weak, nonatomic) IBOutlet UILabel *MessageField;
#property (weak, nonatomic) NSMutableArray *jsonArray;
#property (weak, nonatomic) IBOutlet UILabel *TipLabelField;
-(BOOL)GetTipOfDay;
#end
-didRecieveData can be called multiple times as the bytes and chunks come in. You should move your logic to -connectionDidFinishLoading. This will let you know when the connection is completely done and the data is ready to be parsed.
You're only implementing one of the NSURLConnectionDelegate methods. Try adding this
- (void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
//set up *receivedMutableString as instance variable in .h
if (!receivedMutableString) {
self.receivedMutableString = [[NSMutableString alloc] initWithData:data encoding:NSUTF8StringEncoding];
} else {
NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[receivedMutableString appendString:dataString];
}
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
//Now receivedMutableString contains all json data
...continue with your code
}
NSURLConnection is a bit of overkill if you're just doing a simple GET request (and you're developing for an iOS version that supports blocks). You can do this in a dispatch_async block:
- (void) getData
{
dispatch_async(<some_queue>, ^{
NSError * error = nil;
NSString * response = [NSString stringWithContentsOfURL: stringWithContentsOfURL: requestUrl error: &error];
// process JSON
dispatch_async(dispatch_get_main_queue(), ^{
// Update UI on main thread
}
});
}
As you can see from my example code, you can also perform your JSON processing on the background queue (provided the method you're calling is thread safe). Just pass back to the main queue to update the UI.
Seems like the issue had nothing to do with fetching from the webservice. I had to define my array as __strong. Thanks for all the help. I did get some good ideas on how to do things better.

Links inside Pdf on Webview are not opening in a browser in iPhone

I have parsed urls of pdfs and showing pdf on a webView, but my Links inside webviews are not opening in a browser.i have not used CGPDFDocument. my code is simple :). can anyone help me out.i have seen many similar questions but all are using Quartz.
code :-
#class AppDelegate_iPhone;
#interface PdfShowViewController : UIViewController<UIWebViewDelegate> {
IBOutlet UIWebView *pdfWebview;
AppDelegate_iPhone *appDelegate;
NSMutableData *receivedData;
IBOutlet UIActivityIndicatorView *myIndicator;
IBOutlet UIProgressView *progress;
NSURLRequest* DownloadRequest;
NSURLConnection* DownloadConnection;
long long bytesReceived;
long long expectedBytes;
IBOutlet UILabel *downloadLabel;
}
#property (nonatomic,retain) IBOutlet UILabel *downloadLabel;
#property (nonatomic,retain) IBOutlet UIWebView *pdfWebview;
#property (nonatomic,retain) IBOutlet UIActivityIndicatorView *myIndicator;
#property (nonatomic,retain) IBOutlet UIProgressView *progress;
#property (nonatomic,retain) NSMutableData *receivedData;
#property (nonatomic, readonly, retain) NSURLRequest* DownloadRequest;
#property (nonatomic, readonly, retain) NSURLConnection* DownloadConnection;
#property (nonatomic, retain, readwrite) NSURL *openURL;
-(IBAction)onTapBack;
#end
#implementation PdfShowViewController
#synthesize pdfWebview,myIndicator,progress,receivedData,DownloadRequest,DownloadConnection,downloadLabel,openURL;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
unsigned char byteBuffer[[receivedData length]];
[receivedData getBytes:byteBuffer];
NSLog(#"Data === %ld",receivedData);
NSInteger receivedLen = [data length];
bytesReceived = (bytesReceived + receivedLen);
NSLog(#"received Bytes == %f",bytesReceived);
if(expectedBytes != NSURLResponseUnknownLength)
{
NSLog(#"Expected Bytes in if == %f",expectedBytes);
NSLog(#"received Bytes in if == %f",bytesReceived);
float value = ((float) (bytesReceived *100/expectedBytes))/100;
NSLog(#"Value == %f",value);
progress.progress=value;
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[connection release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
expectedBytes = [response expectedContentLength];
NSLog(#"%f",expectedBytes);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[myIndicator stopAnimating];
[myIndicator removeFromSuperview];
[progress setHidden:YES];
[downloadLabel setHidden:YES];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *pdfPath = [documentsDirectory stringByAppendingPathComponent:#"iPhonePdf.pdf"];
unsigned char byteBuffer[[receivedData length]];
[receivedData getBytes:byteBuffer];
[self.receivedData writeToFile:pdfPath atomically:YES];
[DownloadConnection release];
//Now create Request for the file that was saved in your documents folder
NSURL *url = [NSURL fileURLWithPath:pdfPath];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[pdfWebview setScalesPageToFit:YES];
[pdfWebview loadRequest:requestObj];
}
-(BOOL)webView:(UIWebView *)webView1 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *requestURL = [request URL];
if(navigationType==UIWebViewNavigationTypeLinkClicked)
{
[[UIApplication sharedApplication] openURL:requestURL];
return NO;
}
else
{
return YES;
}
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
pdfWebview.delegate = self;
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
[downloadLabel setText:#"Downloading..."];
[downloadLabel setHidden:NO];
[myIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleWhiteLarge];
myIndicator.hidesWhenStopped = YES;
[myIndicator startAnimating];
// NSString *urlString = [appDelegate.currentBookPressed stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSString *urlString = [appDelegate.currentBookPressed stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
// NSLog(#"The Url Stirng=======%#",urlString);
NSURL *targetURL = [NSURL URLWithString:urlString];
//NSLog(#"Trageted String ------======++++++++%#",targetURL);
DownloadRequest = [NSURLRequest requestWithURL:targetURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:1200.0];
DownloadConnection = [[NSURLConnection alloc] initWithRequest:DownloadRequest delegate:self];
if (DownloadConnection) {
receivedData = [[NSMutableData data]retain];
}
[pdfWebview setScalesPageToFit:YES];
[pdfWebview loadRequest:DownloadRequest];
}
-(IBAction)onTapBack
{
[self dismissModalViewControllerAnimated:YES];
}
#end
here is the link which i am trying to open but not opening :-
No, links inside pdf files loaded in a UIWebView won't open when you tap them by default.
You can go the hard way and parse the links out using Quartz as is shown in this other post I answered.
Or, instead of loading a pdf, can you convert the content you are loading to an html file instead? That would be easier, and the links should work then.
You have to use below delegate method
-(BOOL)webView:(UIWebView *)webView1 shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *requestURL = [request URL] ;
if(navigationType==UIWebViewNavigationTypeLinkClicked)
{
[[UIApplication sharedApplication] openURL:requestURL];
return NO;
}
else
{
return YES;
}
}

I am Getting EXC_BAD_ACCESS while NSURLREQUEST

I am getting EXC_BAD_ACCESS while NSURLREQUEST.
I am giving pdf url from server to to webview through AppDelegate_iPhone's currentBookPressed.
please can anyone tell what is the problem ...
Code:-
#class AppDelegate_iPhone;
#interface PdfShowViewController : UIViewController<UIWebViewDelegate> {
UIWebView *pdfWebview;
AppDelegate_iPhone *appDelegate;
NSMutableData *receivedData;
UIActivityIndicatorView *myIndicator;
IBOutlet UIProgressView *progress;
NSURLRequest* DownloadRequest;
NSURLConnection* DownloadConnection;
long long bytesReceived;
long long expectedBytes;
}
#property (nonatomic,retain) UIWebView *pdfWebview;
#property (nonatomic,retain) UIActivityIndicatorView *myIndicator;
#property (nonatomic,retain) IBOutlet UIProgressView *progress;
#property (nonatomic,retain) NSMutableData *receivedData;
#property (nonatomic, readonly, retain) NSURLRequest* DownloadRequest;
#property (nonatomic, readonly, retain) NSURLConnection* DownloadConnection;
-(IBAction)onTapBack;
#end
#import "PdfShowViewController.h"
#import "AppDelegate_iPhone.h"
#implementation PdfShowViewController
#synthesize pdfWebview,myIndicator,progress,receivedData,DownloadRequest,DownloadConnection;
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[receivedData appendData:data];
unsigned char byteBuffer[[receivedData length]];
[receivedData getBytes:byteBuffer];
NSLog(#"Data === %ld",receivedData);
NSInteger receivedLen = [data length];
bytesReceived = (bytesReceived + receivedLen);
NSLog(#"received Bytes == %f",bytesReceived);
if(expectedBytes != NSURLResponseUnknownLength)
{
NSLog(#"Expected Bytes in if == %f",expectedBytes);
NSLog(#"received Bytes in if == %f",bytesReceived);
float value = ((float) (bytesReceived *100/expectedBytes))/100;
NSLog(#"Value == %f",value);
progress.progress=value;
}
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
//[connection release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
expectedBytes = [response expectedContentLength];
NSLog(#"%f",expectedBytes);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[myIndicator stopAnimating];
[myIndicator removeFromSuperview];
pdfWebview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 40, 320, 420)];
[pdfWebview setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[pdfWebview setScalesPageToFit:YES];
[pdfWebview setAutoresizesSubviews:YES];
[pdfWebview loadRequest:DownloadRequest];
[self.view addSubview:pdfWebview];
//[connection release];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
appDelegate = (AppDelegate_iPhone *)[[UIApplication sharedApplication] delegate];
myIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
myIndicator.center = self.view.center;
myIndicator.hidesWhenStopped = NO;
[self.view addSubview:myIndicator];
[myIndicator startAnimating];
//receivedData = [[NSMutableData alloc] initWithLength:0];
NSLog(#"%#",appDelegate.currentBookPressed);
NSString * urlString = [appDelegate.currentBookPressed stringByAddingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
NSLog(#"%#",urlString);
NSURL *targetURL = [NSURL URLWithString:urlString];
NSLog(#"%#",targetURL);
// Here comes Acception
DownloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:targetURL] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:120.0];
DownloadConnection = [[NSURLConnection alloc] initWithRequest:DownloadRequest delegate:self];
if (DownloadConnection) {
receivedData = [[[NSMutableData data]initWithLength:0]retain];
}
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)viewDidUnload {
[super viewDidUnload];
}
-(IBAction)onTapBack
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)dealloc {
[super dealloc];
[pdfWebview release];
[receivedData release];
}
#end
You should replace line
DownloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:targetURL] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:120.0];
with line
DownloadRequest = [NSURLRequest requestWithURL:targetURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:120.0];
It is because method requestWithURL:cachePolicy:timeoutInterval: in first parameter is waiting for object of NSURL class. In targerURL you have exactly that one.
Moreover in method [NSURL URLWithString:targetURL] (if you will need it) you should pass NSString as a first parameter, but you are passing NSURL.
Your problem in this line
DownloadRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:targetURL] cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:120.0];
The problem in your case arises because parameter for + (id)URLWithString:(NSString *)URLString is NSString and you are passing NSURL and method trying to get the length of the supposed string by calling -length, which exists for NSString but not for NSURL.

NSArray with multiple nested requests

I have an app that uses a segmentedControl. First item is an "All" item, where the rest is created from an array based on result from webservice. When "All" is selected I want to request all the request.
How can I go about this,
NSArray *urls = [NSArray arrayWithObjects:#"http://service/group/1/",
#"http://service/group/2/", nil];
I want to collect all result from the calls into a collection and display it in a UITableView when the "All" item is selected and probably in viewDidLoad.
For the other segments only one of the request is issued and callback with an array that then is used in:
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
I have tried to look at this example for making the request from the array MultipleDownloads
Thanks,
The method in my viewController to initiate the multiple download:
- (void)requestChildrenInBackground {
queue = [[NSOperationQueue alloc] init];
//Todo remove hard coded and get from previous request respons
NSArray *urls = [NSArray arrayWithObjects: #"http://service/1/children",
#"http://service/2/children",
#"http://service/3/children", nil];
NSLog(#"%#", urls);
for (NSString * url in urls)
{
GetSchedule *operation =
[GetSchedule urlDownloaderWithUrlString:url];
[queue addOperation:operation];
}
}
This is how the multiple request gets handled:
#import "GetSchedule.h"
#import "JSON.h"
#import "Authentication.h"
#import "AttendanceReportViewController.h"
#interface GetSchedule ()
- (void)finish;
#end
#implementation GetSchedule
#synthesize appDelegate;
#synthesize username;
#synthesize password;
#synthesize authenticationString;
#synthesize encodedLoginData;
#synthesize schedulesArray;
#synthesize url = _url;
#synthesize statusCode = _statusCode;
#synthesize data = _data;
#synthesize error = _error;
#synthesize isExecuting = _isExecuting;
#synthesize isFinished = _isFinished;
+ (id)urlDownloaderWithUrlString:(NSString *)urlString {
NSURL * url = [NSURL URLWithString:urlString];
GetSchedule *operation = [[self alloc] initWithUrl:url];
return [operation autorelease];
}
- (id)initWithUrl:(NSURL *)url {
self = [super init];
if (self == nil)
return nil;
_url = [url copy];
_isExecuting = NO;
_isFinished = NO;
return self;
}
- (void)dealloc
{
[username release];
[password release];
[encodedLoginData release];
[_url release];
[_connection release];
[_data release];
[_error release];
[super dealloc];
}
- (BOOL)isConcurrent
{
return YES;
}
- (void)start
{
if (![NSThread isMainThread])
{
[self performSelectorOnMainThread:#selector(start) withObject:nil waitUntilDone:NO];
return;
}
self.username = appDelegate.username;
self.password = appDelegate.password;
Authentication *auth = [[Authentication alloc] init];
authenticationString = (NSMutableString*)[#"" stringByAppendingFormat:#"%#:%#", username, password];
self.encodedLoginData = [auth encodedAuthentication:authenticationString];
[auth release];
NSLog(#"operation for <%#> started.", _url);
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
// Setup up the request with the url
NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
initWithURL:_url];
[request setHTTPMethod:#"GET"];
[request setValue:[NSString stringWithFormat:#"Basic %#", encodedLoginData] forHTTPHeaderField:#"Authorization"];
_connection = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (_connection == nil)
[self finish];
else {
_data = [[NSMutableData alloc] init];
}
}
- (void)finish
{
NSLog(#"operation for <%#> finished. "
#"status code: %d, error: %#, data size: %u",
_url, _statusCode, _error, [_data length]);
[_connection release];
_connection = nil;
[self willChangeValueForKey:#"isExecuting"];
[self willChangeValueForKey:#"isFinished"];
_isExecuting = NO;
_isFinished = YES;
[self didChangeValueForKey:#"isExecuting"];
[self didChangeValueForKey:#"isFinished"];
}
#pragma mark -
#pragma mark NSURLConnection delegate
- (void)connection:(NSURLConnection *)connection
didReceiveResponse:(NSURLResponse *)response
{
//[_data release];
//_data = [[NSMutableData alloc] init];
[_data setLength:0];
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
_statusCode = [httpResponse statusCode];
}
- (void)connection:(NSURLConnection *)connection
didReceiveData:(NSData *)data
{
[_data appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// Parse the responseData of json objects retrieved from the service
SBJSON *parser = [[SBJSON alloc] init];
NSString *jsonString = [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding];
NSDictionary *jsonData = [parser objectWithString:jsonString error:nil];
NSMutableArray *array = [jsonData objectForKey:#"Children"];
schedulesArray = [NSMutableArray array];
[schedulesArray addObject:array];
// Callback to AttendanceReportViewController that the responseData finished loading
[attendanceReportViewController loadSchedule];
[self finish];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
_error = [error copy];
[self finish];
}
#end
When all data is received I want to call back to my ViewController and get an array with all data from all request made.
Create a downloader
Create a downloader class using NSURLConnection.
Keep a member variable called downloaderObjectId.
Write a delegate method for this object. This method will pass the downloaded data and downloaderObjectId back to the delegate.
In the delegate.
Create multiple downloader objects(As per your ncessity) with unique value for the downloaderObjectId.
Store these objects in a NSMutableDictionary
Key for each object will be downloaderObjectId. so that when the delegate method is called after download you take the exact object back from the NSMutableDictionary using this key.
Main point.
Each time delegate is called. You should remove the object from dictionary(The object who is done with the download and called his delgate. You can identify this object by the key downloaderObjectId he holds. )
Then check the count of dictionary. If it is zero you can make sure that your downloads are completed. So you can call your viewcontroller.