UITableView partial loading - ios

hi I have an UITableView. It loads numberof data from a web service. What I want to load this tableview 10 by 10.Initially it loads first 10 items. When user scroll to the end of the UITableView it should load next 10 of records from the server. so in my scrollviewDidEndDeclarating delegate I put like this
`
if (scrollView.tag==24) {
[self performSelector:#selector(loadingalbumsongs:) withObject:nil afterDelay:0.1];
}`
but the problem is when I stop the scroll it is getting stuck untill load the table view. Can anybody give me a solution for this
Thanks

Try NSURLCONNECTION that will help you to call asynchronous webservice
A NSURLConnection object is used to perform the execution of a web service using HTTP.
When using NSURLConnection, requests are made in asynchronous form. This mean that you don't wait the end of the request to continue,
This delegate must have to implement the following methods :
connection:didReceiveResponse : called after the connection is made successfully and before receiving any data. Can be called more than one time in case of redirection.
connection:didReceiveData : called for each bloc of data.
connectionDidFinishLoading : called only one time upon the completion of the request, if no error.
connection:didFailWithError : called on error.
EXAMPLE: -
NSData *data = [[NSMutableData alloc] init];
NSURL *url_string = [NSURL URLWithString:
#"Your URL"];
NSURLRequest *request = [NSURLRequest requestWithURL:url_string];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:request
delegate:self];
if (!conn) {
// this is better if you #throw an exception here
NSLog(#"error while starting the connection");
[data release];
}
for each block of raw data received you can append your data here in this method :
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)someData {
[data appendData:someData];
}
connectionDidFinishLoading will call at the end of successfully data receivied

use this code for load more action
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
//scrollView.contentSize.height-scrollView.frame.size.height indicates UItableView scrool end
if (scrollView.contentOffset.y >= scrollView.contentSize.height-scrollView.frame.size.height)
{
if(loadMore)
{
loadmore=no;
//call your Web service
}
}
}

Related

Error in using asynhronous request in iOS%? [duplicate]

I've read through tons of messages saying the same thing all over again : when you use a NSURLConnection, delegate methods are not called. I understand that Apple's doc are incomplete and reference deprecated methods, which is a shame, but I can't seem to find a solution.
Code for the request is there :
// Create request
NSURL *urlObj = [NSURL URLWithString:url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:urlObj cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:30];
[request setValue:#"gzip" forHTTPHeaderField:#"Accept-Encoding"];
if (![NSURLConnection canHandleRequest:request]) {
NSLog(#"Can't handle request...");
return;
}
// Start connection
dispatch_async(dispatch_get_main_queue(), ^{
self.connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES]; // Edited
});
...and code for the delegate methods is here :
- (void) connection:(NSURLConnection *)_connection didReceiveResponse:(NSURLResponse *)response {
NSLog(#"Receiving response: %#, status %d", [(NSHTTPURLResponse*)response allHeaderFields], [(NSHTTPURLResponse*) response statusCode]);
self.data = [NSMutableData data];
}
- (void) connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error {
NSLog(#"Connection failed: %#", error);
[self _finish];
}
- (void) connection:(NSURLConnection *)_connection didReceiveData:(NSData *)_data {
[data appendData:_data];
}
- (void)connectionDidFinishDownloading:(NSURLConnection *)_connection destinationURL:(NSURL *) destinationURL {
NSLog(#"Connection done!");
[self _finish];
}
There's not a lot of error checking here, but I've made sure of a few things :
Whatever happens, didReceiveData is never called, so I don't get any data
...but the data is transfered (I checked using tcpdump)
...and the other methods are called successfully.
If I use the NSURLConnectionDownloadDelegate instead of NSURLConnectionDataDelegate, everything works but I can't get a hold on the downloaded file (this is a known bug)
The request is not deallocated before completion by bad memory management
Nothing changes if I use a standard HTML page somewhere on the internet as my URL
The request is kicked off from the main queue
I don't want to use a third-party library, as, ultimately, these requests are to be included in a library of my own, and I'd like to minimize the dependencies. If I have to, I'll use CFNetwork directly, but it will be a huge pain in the you-know-what.
If you have any idea, it would help greatly. Thanks!
I ran into the same problem. Very annoying, but it seems that if you implement this method:
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
Then connection:didReceiveData: will never be called. You have to use connectionDidFinishLoading: instead... Yes, the docs say it is deprecated, but I think thats only because this method moved from NSURLConnectionDelegate into NSURLConnectionDataDelegate.
I like to use the sendAsynchronousRequest method.. there's less information during the connection, but the code is a lot cleaner.
[NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){
if (data){
//do something with data
}
else if (error)
NSLog(#"%#",error);
}];
From Apple:
By default, a connection is scheduled on the current thread in the
default mode when it is created. If you create a connection with the
initWithRequest:delegate:startImmediately: method and provide NO for
the startImmediately parameter, you can schedule the connection on a
different run loop or mode before starting it with the start method.
You can schedule a connection on multiple run loops and modes, or on
the same run loop in multiple modes.
Unless there is a reason to explicitly run it in [NSRunLoop currentRunLoop],
you can remove these two lines:
[connection scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
[connection start];
or change the mode to NSDefaultRunLoopMode
NSURLConnection API says " ..delegate methods are called on the thread that started the asynchronous load operation for the associated NSURLConnection object."
Because dispatch_async will start new thread, and NSURLConnection will not pass to that other threat the call backs, so do not use dispatch_async with NSURLConnection.
You do not have to afraid about frozen user interface, NSURLConnection providing only the controls of asynchronous loads.
If you have more files to download, you can start some of connection in first turn, and later they finished, in the connectionDidFinishLoading: method you can start new connections.
int i=0;
for (RetrieveOneDocument *doc in self.documents) {
if (i<5) {
[[NSURLConnection alloc] initWithRequest:request delegate:self];
i++;
}
}
..
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
ii++;
if(ii == 5) {
[[NSURLConnection alloc] initWithRequest:request delegate:self];
ii=0;
}
}
One possible reason is that the outgoing NSURLRequest has been setup to have a -HTTPMethod of HEAD. Quite hard to do that by accident though!

Having trouble with multiple NSURLConnection

I've looked around a lot and cant seem to find a proper answer for my problem. As of now I have a network engine and I delegate into that from each of the view controllers to perform my network activity.
For example, to get user details I have a method like this:
- (void) getUserDetailsWithUserId:(NSString*) userId
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:#"%#Details", kServerAddress]]];
request.HTTPMethod = #"POST";
NSString *stringData = [NSString stringWithFormat:#"%#%#", kUserId, userId];
NSData *requestBodyData = [stringData dataUsingEncoding:NSUTF8StringEncoding];
request.HTTPBody = requestBodyData;
NSURLConnection *conn = [[NSURLConnection alloc] init];
[conn setTag:kGetUserInfoConnection];
(void)[conn initWithRequest:request delegate:self];
}
And when I get the data in connectionDidFinishLoading, I receive the data in a NSDictionary and based on the tag I've set for the connection, I transfer the data to the required NSDictionary.
This is working fine. But now I require two requests going from the same view controller. So when I do this, the data is getting mixed up. Say I have a connection for search being implemented, the data from the user details may come in when I do a search. The data is not being assigned to the right NSDictionary based on the switch I'm doing inside connectionDidFinishLoading. I'm using a single delegate for the entire network engine.
I'm new to NSURLConnection, should I setup a queue or something? Please help.
EDIT
Here's the part where I receive data in the connectionDidFinishLoading:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
if ([connection.tag integerValue] == kGetUserDetails)
networkDataSource.userData = self.jsonDetails;
if ([connection.tag integerValue] == kSearchConnection)
networkDataSource.searchData = self.jsonDetails;
}
and after this I have a switch case that calls the required delegate for the required view controller.
Anil here you need to identify for which request you got the data,
simplest way to check it is as below,
- (void)connectionDidFinishLoading:(NSURLConnection *)conn
{
// Check URL value for request, url for search and user details will be different, put if condition as per your need.
conn.currentRequest.URL
}
Try using conn.originalRequest.URL it will give original request.
You can do in many ways to accomplish your task as mentioned by others and it will solve your problem . But if you have many more connections , you need to change your approach.
You can cretae a subclass of NSOperation class. Provide all the required data, like url or any other any informmation you want to get back when task get accomplish , by passing a dictionary or data model to that class.
In Nsoperation class ovewrite 'main' method and start connection in that method ie put your all NSURRequest statements in that method. send a call back when download finish along with that info dict.
Points to be keep in mind: Create separte instance of thet operation class for evey download, and call its 'start method'.
It will look something like :
[self setDownloadOperationObj:[[DownloadFileOperation alloc] initWithData:metadataDict]];
[_downloadOperationObj setDelegate:self];
[_downloadOperationObj setSelectorForUpdateComplete:#selector(callBackForDownloadComplete)];
[_downloadOperationObj setQueuePriority:NSOperationQueuePriorityVeryHigh];
[_downloadOperationObj start];
metaDict will contain your user info.
In DownloadFileOperation class you will overwrite 'main' method like :
- (void)main {
// a lengthy operation
#autoreleasepool
{
if(self.isCancelled)
return;
// //You url connection code
}
}
You can add that operation to a NSOperationQueue if you want. You just need to add the operation to NSOperationQueue and it will call its start method.
Declare two NSURLConnection variables in the .h file.
NSURLConnection *conn1;
NSURLConnection *conn2;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection{
if(connection == conn1){
}
else if(connection == conn2){
}
}

Multiple JSON requests in iOS

I wish to fetch data for an array of URLs that return JSON data. I am trying the following code:
for (int i =0; i<numberOfDays; i++)
{
NSData *data = [NSData dataWithContentsOfURL:[wordURLs objectAtIndex:i]];
NSLog(#"%#",[wordURLs objectAtIndex: i]);
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
}
'wordURLs' are the array of URLs and in my 'fetchedData:' method, I save the returned JSON data to a plist file.
The issue is that for all number of times that the loop runs, the data is returned for only one/two particular URLs (i.e. say for the urls at indices at 1 and 3, or 1 and 2 etc). I log and see that the URLs are different for each time the 'data' variable is initialized.
What is a better way of doing this?
I have used NSJSONSerialization for parsing JSON.
There are much better ways of doing this. The problem with what you are trying to do is that it is synchronous, which means your app will have to wait for this action to be completed before it can do anything else. I definitely would recommend looking into making this into an asynchronous call by simply using NSURLConnection and NSURLRequests, and setting up delegates for them.
They are relatively simple to set up and manage and will make your app run a million times smoother.
I will post some sample code to do this a little later once I get home.
UPDATE
First, your class that is calling these connections will need to be a delegate for the connections in the interface file, so something like this.
ViewController.h
#interface ViewController: UIViewController <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
NSMutableData *pageData;
NSURLConnection *pageConnection;
}
Then you will need to create/initialize the necessary variables in you implementation
ViewController.m
-(void) viewDidLoad {
pageData = [[NSMutableData alloc] init];
NSURLRequest *pageRequest= [[NSURLRequest alloc] initWithURL:pageURL cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:4];
pageConnection = [[NSURLConnection alloc] initWithRequest:pageRequestdelegate:self];
}
Then you also need the delegate functions that will get called as the data is retrieved.
-(void) connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
if (connection == pageConnection) {
[pageData appendData:data];
}
}
-(void) connectionDidFinishLoading:(NSURLConnection *)connection {
if (connection == pageConnection) {
// Do whatever you need to do with the data
}
}
-(void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
if (connection == pageConnection) {
// Do something since the connection failed
}
}
Of course this example only includes one URL being loaded, but you could make it as many as you want. You will of course have to keep track of all of the necessary NSURLConnections so you know where to put the data you received, as well as what actions to take in case of a failure or the connection being completed successfully, but that is not a hard extension from what I have given.
If you see any glaring errors or something does not work, please let me know.

Access UI component from other thread in iOS

I have an issue on how to refresh the UI for iOS apps. What I wanted to achieve is this:
Show data in UITableView based on data retrieved from web service
The web service should be called from a separate thread (not main thread)
After the data is retrieved, it will refresh the contents of UITableView with the retrieved data
It is due so that the UI will not hang or the app will not block user input while in the process of receiving data from the web service in bad network connection
To do that, I create the following source code:
- (void)viewDidLoad
{
[super viewDidLoad];
NSURL *myURL = [[NSURL alloc] initWithString:[Constant webserviceURL]];
NSURLRequest *request = [NSURLRequest requestWithURL:myURL cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:60];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
[self myparser] = [[MyXMLParser alloc] initXMLParser];
[parser setDelegate:myparser];
BOOL success = [parser parse];
if (success) {
// show XML data to UITableView
[_tableView performSelectorOnMainThread:#selector(reloadData) withObject:[myparser xmldata] waitUntilDone:NO];
}
else {
NSLog(#"Error parsing XML from web service");
}
}
==================
Is my implementation correct? Anybody know how to resolve it?
You would want to call
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
It will make the call to get the Data on a different thread then when the data pulled down or it had problems download data from the url it will call your handler block on the same thread as the original call was made.
Here is one way to use it: https://stackoverflow.com/a/9409737/1540822
You can also use
- (id)initWithRequest:(NSURLRequest *)request delegate:(id < NSURLConnectionDelegate >)delegate
And this will call one of your NSURLConnectionDelegate methods when data is downloaded in chucks. If you going to have large data then you may want to use this so that you don't spend too much time in the response.

In iOS, how can I load modal window with the data received from some NSURLConnection?

In my iPad application, I want to load a modal window with some data.
But those data can be retrieved from a web service call. So, I have created another class and in that class's connectionDidFinishLoading I can have the response data. As the web service call is asynchronous, I have to wait for the data to load the modal window. Can anyone help me with some example code? Should I think in different way?
Thank you all for the prompt reply.
My problem was solved using the NSNotificationCenter. This tutorial was helpful http://www.youtube.com/watch?v=WB-QCv_4ANU&feature=plcp
Either you can load modal window from connectionDidFinishLoading method. Or you can use delegates to pass data from connectionDidFinishLoading metod to the window that you are going to present. Refer this tutorial.
You start the connection this way:
NSURL *url = [NSURL URLWithString:<#your url string#>];
NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
myData = [[NSMutableData alloc] init];
con = [[NSURLConnection alloc] initWithRequest:request delegate:self];
And you need to implement NSURLConnectionDelegate delegate.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//append data to your NSMutableData object
[myData appendData: data];
}
- (void)connection:(NSURLConnection *)connection
didFailWithError:(NSError *)error
{
//handle the error
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//here you can use your NSMutableData object, fill your window with the data etc.
<#your code#>
}
This is just an example. You can read more about it in NSURLConnectionDelegate Protocol Reference.

Resources