I am stuck and need some help understanding why this is not working.
I want to be able to download the HTML of a page and then format it to show correctly, the code inside the second class (spriing) will download and display the HTML in a UITextView if it is placed inside the ViewController, however this is breaking the MVC right?
So could anyone tell me why I am getting the out of scope error on the mStringData variable?
My classes are below:
I have one class which is a view controller;
//Class for the download and processing of data from website
#import "FirstViewController.h"
@implementation FirstViewController
// The designated initializer. Override to perform setup that is required before the view is loaded.
//- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
// if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
// // Custom initialization
//}
// return self;
//}
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
spriing = [Spriing new];
[spriing downloadData:@"http://www.spriing.co.uk/services/"];
SpriingTxt.text = spriing.mStringData;
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[mRecData release];
[mStringData release];
}
And a separate class;
#import "Spriing.h"
@implementation Spriing
@synthesize mStringData;
@synthesize mRecData;
- (void)downloadData: (NSString*) URL{
mBaseURL = URL;
// Create the request.
NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:mBaseURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
mCon=[[NSURLConnection alloc] initWithRequest:request delegate:self];
if (mCon)
{
// create var to store data
mRecData = [[NSMutableData data] retain];
}
else
{
// Inform the user that the connection failed.
}
}
//If the connection is reset
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
//reset the data length
[mRecData setLength:0];
}
//Obtaining new data
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//Add any newly recieved data to the currently stored data
[mRecData appendData:data];
}
//If something went wrong
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
//Release the connection
[mCon release];
//Release the data
[mRecData release];
//Alert the user
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Error!"
message:@"No internet connection!" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] autorelease];
[alert show];
[alert release];
}
//When its done
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//NSLog(@"finished");
// Once this method is invoked, "responseData" contains the complete result
self.mStringData = [[[NSString alloc] initWithData:mRecData encoding:NSUTF8StringEncoding] retain];
//NSLog(@"%@", mStringData);
self.mStringData = [self processData:mStringData];
//NSLog(@"%@", mStringData);
//SpriingTxt.text = mStringData;
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
//mStringData = nil;
}
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
{
[mBaseURL autorelease];
mBaseURL = [[request URL] retain];
return request;
}
-(NSString*) processData: (NSString*) string
{
NSMutableString *html = [NSMutableString stringWithCapacity:[string length]];
NSScanner *scanner = [NSScanner scannerWithString:string];
NSString *tempText = nil;
while (![scanner isAtEnd])
{
[scanner scanUpToString:@"<" intoString:&tempText];
if (tempText != nil)
[html appendString:tempText];
[scanner scanUpToString:@">" intoString:NULL];
if (![scanner isAtEnd])
[scanner setScanLocation:[scanner scanLocation] + 1];
tempText = nil;
}
return html;
}
- (void) dealloc
{
[super dealloc];
//[mStringData release];
}
@end
You are starting an asynchronous request for a URL which will take some time. Although it returns immediately, it doesn’t imply that the data has been download.
NSURLRequest‘s delegate will be notified when the data has finished downloading. It is not until then that there is data inmStringDatawhich is probablynilprior to being assigned the downloaded data. So when you doSpriingTxt.text = spriing.mStringData;immediately after an asynchronous request without the data being downloaded,SpriingTxt.textis assignednil.To resolve this, you can either make a synchronous request which will block until the data has been downloaded which is generally a bad idea or you can message via delegates or notifications to your view controller when the data of your asynchronous request has been downloaded.
To implement the delegate
Delegates are implemented using protocols. You will create a
delegateproperty in the delegating object which would beSpriingas it will let the delegate know when the string has been downloaded and the view controller will be its delegate as it wants to know when the data is available so that it can update its view. Delegates are usually not retained as most times it is the object that creates them that becomes its delegate. So retaining the delegate would create a retain cycle in such instances. There are lots of tutorials about creating the delegates. A rough implementation would be,in
Spriing.hin
Spriing.min the view controller,