I have had this problem and i went through so many posts here on stack overflow and everywhere else and couldnt find a solution. Im running it on the main thread as well. Code as follows.
#interface JsonViewController : UIViewController <UIActionSheetDelegate,UIWebViewDelegate,NSURLConnectionDelegate>
{
....
}
#implementation JsonViewController
- (void)viewDidLoad
{
[super viewDidLoad];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com"] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
rssFeedDetailViewConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
NSLog(#"PRINTING RSS FEED %#", rssFeedDetailViewConnection);
[rssFeedDetailViewConnection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[rssFeedDetailViewConnection start];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Hello");
responseData = [[NSMutableData alloc] init];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
NSLog(#"Hello");
[responseData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(#"Hello");
[responseData release];
[connection release];
// Show error message
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(#"Hello");
// Use responseData
[responseData release];
[connection release];
}
Any help would be greatly appreciated. Ive been stuck with this for two days now..
You don't need these statements:
[rssFeedDetailViewConnection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[rssFeedDetailViewConnection start];
since you're using initWithRequest:delegate:. This call already starts loading the data.
What happens if you remove these particular statements?
More info on the NSURLConnection.
Have a boolean called finished and add this code where ever you have written your NSURLConnection Code.
while(!finished) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
and in your connectionDidFinishLoading just add this
finished = TRUE;
and that works. Its not the best solution i understand but it works.
Related
I have to classes A and B . My B class having the method for connection with the server. I am calling this method from class A.I have implemented the delegate for NSURLConnection.class A having check connectivity function which is having the return type as a BOOL . I am invoking the ping method of class B from this method as follow:
class A:
-(BOOL)checkConnectivity:(Server *)newServer
{
[b ping];
return FALSE;
}
class B:
-(void)ping
{
NSURL *url=[[NSURL alloc]initWithString:#"my url"];
request=[NSMutableURLRequest requestWithURL:url];
connection=[[NSURLConnection alloc]initWithRequest:request delegate:self];
if(connection)
{
webData=[NSMutableData data];
}
}
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *) data
{
[webData appendData:data];
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Finished loading");
}
there is no issue with the url. Then whats wrong?why delegate methods are not invoking ?
Check u have added this:
#interface yourViewController : UIViewController <NSURLConnectionDelegate>
Now do this in your ping method:
NSURLConnection * connection = [[NSURLConnection alloc]
initWithRequest:request
delegate:self startImmediately:NO];
[connection scheduleInRunLoop:[NSRunLoop mainRunLoop]
forMode:NSDefaultRunLoopMode];
[connection start]
I sent NSURLConnection request it is working fine. Now I want to refresh the information i.e. resend the NSURLConnection.Refresh is working when call from IBAction of button. But is not working from NSThread method. How to I solve this problem. Here NSThread function for running the system time. When the time is equal to 1:00 am I want to refresh the API. But it is not call the delegate of NSURLConnection.
This is NSURLConnection code:
-(void)displays:(model *)place
{
NSString *strs=[#"http://www.earthtools.org/timezone-1.1/" stringByAppendingString:[NSString stringWithFormat:#"%#/%#",place.latitude,place.longitude]];
NSMutableURLRequest *request=[NSMutableURLRequest requestWithURL:[NSURL URLWithString:strs]];
NSURLConnection *reqTimeZone=[NSURLConnection connectionWithRequest:request delegate:self];
[reqTimeZone start]; //here request not get start
}
Above code is with in function called "displays" argument is one instance of class it has all place details.
NSthread function code:
- (void) setTimer {
//assign current time
[self countDown];
}
- (void) countDown {
//count the current time
if(hrs==12&& meridian==#"pm")
[self display:(placedetails)];//it calls the displays function but NSURLConnection is not get start.
[NSThread detachNewThreadSelector:#selector(setTimer) toTarget:self withObject:nil];
}
Above display function is called placedetails assigned but NSURLConnection delegate is not called.
For the delegate methods to be called, you need to attach your thread's runloop to NSURLConnection. Since you are creating a thread and not attaching NSURLConnection to thread's RunLoop, connection delegate methods won't get fired.
Here is an example:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// I am creating a button and adding it to viewController's view
UIButton *bttn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[bttn setFrame:CGRectMake(100.0f, 200.0f, 120.0f, 50.0f)];
[bttn setTitle:#"Download" forState:UIControlStateNormal];
[bttn addTarget:self action:#selector(spawnThreadForDownload) forControlEvents:UIControlEventTouchUpInside];
[[self view] addSubview:bttn];
}
- (void)spawnThreadForDownload
{
[NSThread detachNewThreadSelector:#selector(downloadAndParse) toTarget:self withObject:nil];
}
- (void)downloadAndParse
{
#autoreleasepool {
NSURL *url = [NSURL URLWithString:#"http://apple.com"];
NSURLRequest *req = [NSURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:20.0f];
NSURLConnection *conn = [NSURLConnection connectionWithRequest:req delegate:self];
// Run the currentRunLoop of your thread (Every thread comes with its own RunLoop)
[[NSRunLoop currentRunLoop] run];
// Schedule your connection to run on threads runLoop.
[conn scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
}
// NSURLConnectionDelegate methods
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"Connection failed with error: %#",[error localizedDescription]);
}
// NSURLConnectionDataDelegate methods
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Connection finished downloading");
}
i have this function which call a function to check CMS for info. but the UIActivityIndicatorView freeze till the check is completed. not sure why.
EDIT: one thing funny, i commented out the performselector. the UIActivityIndicatorView still freezed. until i tapped my back button then it started to spin....
i'm using storyboard, iOS 5
-(void)showLoading
{
[activity startAnimating];
//loading is a label to show "File Loading"
loading.alpha =1;
//is a label to show a 0.3 alpha of the label
blackOverlay.hidden =0;
[self performSelector:#selector(updateFromInternet:) withObject:#"a" afterDelay:2];
//[self updateFromInternet:#"a"];
}
-(void)updateFromInternet:(NSString *)urlStr
{
NSString *URLString = #"http://sites.google.com/site/iphonesdktutorials/xml/Books.xml";
NSURL *updateDataURL = [NSURL URLWithString:URLString];
NSMutableURLRequest *WPXMLFetchRequest = [NSMutableURLRequest requestWithURL:updateDataURL];
self.receivedData = [NSMutableData data];
self.updateConnection = [NSURLConnection connectionWithRequest:WPXMLFetchRequest delegate:self];
NSLog(#"Checking update at : %#", updateDataURL);
//[self.updateConnection cancel];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
////NSlog(#"Receiving data");
[self.receivedData appendData:data];
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
////NSlog(#"Failed to receive data");
self.receivedData = nil;
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
////NSlog(#"Received response from data");
[self.receivedData setLength:0];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *data=[[NSString alloc]initWithData:self.receivedData encoding:NSUTF8StringEncoding];
NSLog(#"data %#",data);
NSError *parseError = nil;
//NSDictionary *xmlDict = [XMLReader dictionaryForXMLData:self.receivedData error:&parseError];
self.receivedDict = [XMLReader dictionaryForXMLData:self.receivedData error:&parseError];
[self showDataOnScrollView];
}
You should delay the "heavy" function a bit and let the Activity Indicator fire.
try adding a 2.0 and not 2 to your delay (I would use a much smaller value - say 0.3)
[self performSelector:#selector(updateFromInternet:) withObject:#"a" afterDelay:0.3];
if this does not solve's your problem you should look (or post) the code related to the extra stuff you have in your code like : loading.alpha =1; and blackOverlay.hidden =0; which I assume are elements added to the Activity Indicator
From my ApplicationDelegate, I'm doing an NSURLConnection fetch over the network (it's wrapped in a class, as you'll see below). This one seems to work correctly: I get all the data in didReceiveData and I get the completion call connectionDidFinishLoading. At the end of connectionDidFinishLoading, I instantiate one or more of a slightly different kind of wrapper class, but they're essentially the same thing. The problem is that the second NSURLConnection's delegate is never having it's methods called.
I've looked at many different answers, but all to no avail. I'm not spawning any new threads and all the [NSThread isMainThread] checks I've littered throughout the code return true.
I'm stumped. Can anyone help me out? Here's the relevant code:
App Delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
ConnectionWrapper* w = [[ConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<url>]];
[w beginFetch];
return YES;
}
...
-(void)fetchCompleted:(NSURL*)url directory:(NSString*)directory
{
NSLog(#"fetch completed");
}
-(void)fetchFailed:(NSURL*)url
{
NSLog(#"fetch failed");
}
...
ConnectionWrapper:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
-(void)fetchCompleted:(NSURL*)URL
{
NSLog(#"completed: %#", URL);
}
-(void)fetchFailed:(NSURL*)URL
{
NSLog(#"failed");
}
DifferentConnectionWrapper:
-(id)initWithParams:(id)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"append");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
NSLog(#"got response");
[responseData setLength:0];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
NSLog(#"got data");
[responseData appendData:data];
}
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
NSLog(#"image saver completed: %#", connURL);
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(#"error");
}
ConnectionWrapper and DifferentConnectionWrapper have similar functions, but there's other logic that I've omitted here for brevity.
thanks for the help. I appreciate it.
A couple of things: I don't see a didFailWithError: in your first wrapper class, and (a little off topic) are you leaking memory with your DifferentConnectionWrapper *w ?
Anyway, what I would try is: see if you can invoke DifferentConnectionWrapper directly from the appDelegate instead of the ConnectionWrapper.
And I would try to decouple the two calls in any event. When the first one finishes, and calls appDelegate, can't you launch your DifferentConnectionWrapper from there?
I realize this doesn't explain your problem, but you might get it working (and which of THOSE two things is more important, is an entirely different debate.)
I believe the problem is that you’re releasing the URL connection in -beginFetch:
-(void)beginFetch
{
NSURLRequest* request = [[NSURLRequest alloc] initWithURL:connURL];
NSURLConnection* conn = [[NSURLConnection alloc] initWithRequest:request delegate:self];
[conn release];
[request release];
}
The URL connection object should be kept alive and released when the connection has finished loading:
- (void) connectionDidFinishLoading: (NSURLConnection*) connection
{
... parsing ....
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
DifferentConnectionWrapper* w = [[DifferentConnectionWrapper alloc] initWithParams:self
url:[NSURL URLWithString:<different url>]];
[w beginFetch];
}
or when there’s been an error:
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
// *** Release the connection and whatever data you’ve kept related to
// this particular connection
[connection release];
[responseData release];
// *** or [responseData setLenght:0]; depending on how you’re
// managing responseData
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
Edit: Your initialiser is a tad weird:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
delegate = d;
connURL = url;
return [self init];
}
There’s no way to know what happens unless we see the code for -init and, at any rate, this should be the designated initialiser, so it shouldn’t be sending -init to self anyway. Furthermore, you should be retaining the url object that’s being passed to the initialiser.
The following makes more sense:
-(id)initWithParams:(id<ConnectionWrapperDelegate>)d url:(NSURL*)url
{
self = [super init];
if (self) {
delegate = d;
connURL = [url retain];
}
return self;
}
Don’t forget to release the url object in -dealloc or when you’re assigning another value to connURL.
OK. It turns out that this bug was caused by something I missed. I was going into a hard spin right after that second request, which would probably screw up just about anything. Once I fixed that problem, everything worked just fine.
Thanks for the help.
I want my application to download some data from the internet, in iPhone SDK documentation
i found NSURLConnection class, which is used for downloading, Am i right?
I wrote the same code as it is in the documentation and ran it. Connection was created successfully, but no data were downloaded. connectionDidFinishLoading is fired after sec or two but with no data in result. Problem is, that didRecieveData method is never fired. I dont know why, i searched the internet, but every result was the same code as it is in the documentation. Could you give an advice please? Thanks for every reply
My downloader class source code is below.
Downloader.h
#interface Downloader : NSObject {
NSURLConnection *conn;
//Array to hold recieved data
NSMutableData *recievedData;
}
#property (nonatomic, retain) NSURLConnection *conn;
#property (nonatomic, retain) NSMutableData *recievedData;
- (void)downloadContentsOfUrl:(NSURL *)url;
#end
Downloader.m
#import "Downloader.h"
#implementation Downloader
#synthesize recievedData, conn;
- (void)connection:(NSURLConnection *)connection didRecieveResponse:(NSURLResponse *)response
{
NSLog(#"did recieve response");
[recievedData release];
recievedData = nil;
}
- (void)connection:(NSURLConnection *)connection didRecieveData:(NSData *)data
{
NSLog(#"did recieve data");
//Append the new data to the recieved data
[recievedData appendData:data];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//Release the connection and the data object
[connection release];
[recievedData release];
NSLog(#"Connection failed! Error - %# %#", [error localizedDescription],
[[error userInfo] objectForKey:NSErrorFailingURLStringKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//ToDo with data
//[recievedData writeToFile:#"data" atomically:YES];
NSLog(#"downloaded");
NSLog(#"%u", [recievedData length]);
//Release the connection and the data object
[connection release];
[recievedData release];
}
- (void)downloadContentsOfUrl:(NSURL *)url
{
//Create the connection
//Create the request
NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
//Create the connection with the request and start loading the data
conn = [[NSURLConnection alloc] initWithRequest:urlRequest delegate:self
startImmediately:YES];
if(conn)
{
//Create the NSMutableData that will hold the recieve data
recievedData = [[NSMutableData data] retain];
NSLog(#"Connection success!");
}
else
{
NSLog(#"Can't download this file!");
}
}
- (void)dealloc
{
[conn release];
[recievedData release];
[super dealloc];
}
You've misspelt "receive":
// Your signature
- (void)connection:(NSURLConnection *)connection didRecieveData:(NSData *)data;
// Correct signature
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
You have a typo in the name of your didReceiveData method (i before e, except after c :-)
Thus it will look like your class doesn't implement that (optional) selector and it will be silently ignored.