NSURLConnection threading problem - iphone

i have a big problem and i need your help. Here's what i need to accomplish:
The user select a row from a
TableView
A new view controller is pushed in
the NavigationController, and
displays only a "Loading" message
Meanwhile some data is read from an
XML file (via http)
When the data has been read, an
NSUConnection is used to load an
image from an URL (this URL is part
of the data)
While the image is still loading,
the other data is displayed on the
screen
The image has been downloaded and is
shown, completing the appearance of
the view
The big problem is that i can't use detachNewThreadSelector and NSURLConnection together!
So how can i make a workaround for this? How would you do this?
Thank you VERY much!

You can use following approach...(if you are using asynchronous request)
When your application comes in - (void)connectionDidFinishLoading:(NSURLConnection *)connection ... add a NSInvocationOperation object in NSOperationQueue (which you can handle at application level, by synthesizing it in appDelegate) ..
create NSInvocationOperation as follows..(in connectionDidFinishLoading)
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:#selector(parseIt) object:nil];
[appDelegate.operationQueue addOperation:operation];
[operation release];
-(void) parseIt
{
//ask for parsing stuff....what you have earlier wrote directly in connectionDidFinishLoading
}
Thanks,

I would use a NSTimer to solve the problem using detachNewThreadSelector and NSURLConnection together.
I have similar scenario where there is a downloading Progress UIViewController showing till the file getting complete, here is what i do:
I Draw a loading View contains a Activity Indicator for example.
I initialize a NSTimer to keep checking if the file is complete.
I call the method that contains the Download Logic.
[1]
-(void) vManageFileRequest
{
[self.oFilesManager vGetSingleFileRequest];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(vValidateFileRequest) userInfo:nil repeats:NO]];
}
[2]
[self performSelectorOnMainThread:#selector(vManageFileRequest) withObject:nil waitUntilDone:NO];

Related

iPhone:UI blocked when downloading data using NSURLConnection

I am using the NSURLConnection to download a video file from the server, at the same time playing the video by passing different url link to the movieplayer.
The problem is some blocking of the UI. During downloading we are unable to interact with the UI, like player zoom, pause button are blocked.
Code is like this for connection:_
connection1=[[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]] delegate:self];
in same mithod we are calling the
[playerInstance Play]
Please can you explain me where the problem is.
I can't understand your problem exactly. But I think you doing the two works (downloadig, playing file) on a same thread, probably main thread. So this may happen. So try to run the two processes in a separate threads.
[self performSelectorOnMainThread:#selector(playfile:) withObject:nil waitUntilDone:NO];
[self performSelectorInBackground:#selector(downloadfile:) withObject:nil];
You should make function for NSUrl operation and if it is already made call this function in following way for asynchronous communication.
[self performSelector:#selector(method) withObject:nil afterDelay:1];

UIWebView EXC_BAD Access

Hy
I've got a UIView. In one method, I alloc a WebView, and set it's to a retain property.
self->webView= [[UIWebView alloc] initWithFrame:self.frame];
Then I start to load a HTML string. After it's loaded, I resize the view and start a callBack to the superview to resize. It's working.
My problem is that, if the user go back before the view has been loaded, the view's are released. Then my WebView throw a BAD_ACCESS.
Here is the dealloc method:
-(void)dealloc{
[self.webView setDelegate:nil];
[self.webView stopLoading];
[self setWebView:nil];
[htmlStr release];
[super dealloc];}
The callback trace is shown in the screenshot. The interesting is that, if I don't release the WebView it is work's like the charm. If I release the WebView, then when it's deallocated, I get an error message in the log:
![bool _WebTryThreadLock(bool), 0x4e05150: Tried to obtain the web lock from a thread other than the main thread or the web thread. This may be a result of calling to UIKit from a secondary thread. Crashing now...][1]
EDIT: It has been fixed. It turns out, that my image loading method was guilty. I've start a new thread (NSOperationQueue and NSInvocationOperation in that) to load an image, and make a performSelectorOnMainThred: when it's finished. Whit that, I've loaded more than hundred small (1-2 KB) image, on every page switch, which was a really big overhead. When I wrote a method which download the images in one thread one by one, this bug has never came again
You are modifying UI from other tread than main. This is forbidden as UIKit is not thread-safe (hence the crash...). If you want to modify the UI from another thread, you must use:
performSelectorOnMainThread:withObject:waitUntilDone:
Other thing I've notice in your code is that you incorrectly release your properties in -dealloc. You should not use synthesized setters like this:
[self setWebView:nil]; // same as self.webView = nil;
You should not, because it can bring you lots of problems if you start using KVO (Key-Value Observing) on you properties... Instead just write:
[webView release];
or, if you want to avoid "The Heisenbug":
[webView release], webView = nil;
EDIT: you can also benefit from answer to this SO question: How to safely shut down a loading UIWebView in viewWillDisappear?
Dont call it with self.webView in dealloc, just use webView:
- (void)dealloc {
if ([webView isLoading])
[webView stopLoading];
[webView setDelegate:nil];
[webView release], webView = nil;
[super dealloc];
}
It has been fixed. It turns out, that my image loading method was guilty. I've start a new thread (NSOperationQueue and NSInvocationOperation in that) to load an image, and make a performSelectorOnMainThred: when it's finished.
Whit that, I've loaded more than hundred small (1-2 KB) image, on every page switch, which was a really big overhead. When I wrote a method which download the images in one thread one by one, this bug has never came again.

iPhone UILabel not updating

I know there are lots of similar questions floating around, but none of the answers seem to fix my problem. I have an app that uses an NSURLConnection to download a file, and then does some calculations on the downloaded file. I set up a UILabel to display the current loading status (eg: "Loading file", "Parsing file"). I update the UILabel in the didReceiveResponse and connectionDidFinishLoading function of the NSURLConnection delegate, as well as some other places in my code. I update it by calling the following function:
[self performSelectorOnMainThread:#selector(updateProgress) withObject:nil waitUntilDone:NO]
where -(void)updateProgress is a function I defined to call [theLabel setNeedsDisplay]. I NSLog'd it, like
NSLog(#"theLabel: %#\n",theLabel.text);
and the information is updated correctly, but the label doesn't actually update in the view. Also, updateProgress is only called AFTER everything is loaded. It updates the label THEN, which is hardly useful. Any suggestions?
The NSURLConnection is blocking the main thread (no updates will be performed on the view until it finishes).
You can perform updateProgress in the background:
[self performSelectorInBackground:#selector(updateProgress) withObject:nil]
The first line of updateProgress should be:
NSAutoReleasePool *pool = [[NSAutoReleasePool alloc]init];
The last lines should be:
[pool release];
pool = nil;
http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSAutoreleasePool_Class/Reference/Reference.html
Of course, you can also perform the NSURLConnection in the background. Then you can update the label on the main thread.

Threading in iphone

I m using NSoperationQueue for load song from server.
This code execute when click on diff-diff buttons.
NSOperationQueue *queue;
NSInvocationOperation *operation = [[NSInvocationOperation alloc]
initWithTarget:self selector:#selector(loadImage)object:nil];
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
[queue addOperation:operation];
Problem is that when user click ie.Rama.aac then loading continue in this duration if he click krishna.aac then this process also goes into that queue.and conflicting is there.
user is finally requesting for krishna but in result first download rama.aac then krishna.aac.
I m using [queue cancelAllOperations] but it not works.
How i solve this?
Implement your own NSOperation subclass. NSOperation has isCancelled property set when cancelAllOperations is called on the queue.
If I'm not mistaken using NSOperations to load data from a network is not advised. You should use the asynchronous loading NSURLConnection provides.

implementing UIActivityIndicatorView while NSData dataWithContentsOfURL is downloading

I am downloading an mp3 using NSData dataWithContentsOfURL:url. This takes a while and while the file is downloading the application hangs. I want to handle well and ideal would like to show the download progress but can't find methods for this.
It is in a UIViewController and I have made a first attempt by putting in a UIActivityIndicatorView and start it spinning before I start the download, then stop it spinning after but nothing appears.
So my question really is please could someone tell me what the best way to handle this is? Thanks so much
Nothing will appear because your main thread is blocked doing the download, and the main thread is where UI updates occur.
You should use NSUrlConnection to download asynchronously and implement the delegate methods to start/stop your spinner.
Alternatively if you want to stick with NSData's dataWithContentsOfURL:url you should do this on a separate thread and update the spinner on the main thread before and after you call it.
You can achieve this while still using synchronous methods, but you need to give the run loop a chance to start animating the activity indicator before you start the download.
You can achieve this by using either performSelector:withObject:afterDelay: with delay 0 to put a run loop between your animation start and the download, or (worse style, more risky) you can directly invoke the run loop within your code.
Sample code:
- (void)loadPart1 {
activityIndicator = [[[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIA...StyleGray]
autorelease];
activityIndicator.frame = myFrame;
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
[self performSelector:#selector(loadPart2) withObject:nil afterDelay:0];
}
- (void)loadPart2 {
[NSURLConnection sendSynchronousRequest:request returningResponse:&response
error:&error];
[activityIndicator stopAnimating];
}
More details here:
http://bynomial.com/blog/?p=15
(scroll down to Solution 1 or Solution 2).