我陷入困境,需要帮助理解为什么这不起作用。
我希望能够下载页面的HTML然后将其格式化为正确显示,第二类(spriing)中的代码将下载并在UITextView中显示HTML,如果它放在ViewController中,这打破了MVC吧?
那么有人能告诉我为什么我在mStringData变量上出现超出范围的错误吗?
我的课程如下:
我有一个类是视图控制器;
//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];
}
另一个班级;
#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
答案 0 :(得分:3)
您正在启动对URL的异步请求,这需要一些时间。虽然它立即返回,但并不意味着数据已下载。数据下载完成后,将通知NSURLRequest
的代理人。直到那时,mStringData
中的数据在被分配下载数据之前可能是nil
。因此,当您在没有下载数据的异步请求后立即执行SpriingTxt.text = spriing.mStringData;
时,会为SpriingTxt.text
分配nil
。
要解决此问题,您可以创建一个同步请求,该请求将在数据下载之前阻塞,这通常是一个坏主意,或者当您的异步请求的数据已经过时,您可以通过委托或通知向您的视图控制器发送消息下载。
实施代理
代表是使用协议实现的。您将在委派对象中创建delegate
属性,该属性为Spriing
,因为它将让代理知道何时下载字符串并且视图控制器将成为其委托,因为它想知道何时数据可用,以便它可以更新其视图。代理通常不会被保留,因为大多数时候它是创建它们成为其委托的对象。因此,保留委托将在这种情况下创建保留周期。有很多关于创建委托的教程。粗略的实施将是,
Spriing.h
中的
@protocol SpriinDelegate;
@interface Spriing:... {
id<SpriingDelegate> delegate;
...
}
@property (nonatomic, assign) id<SpriingDelegate> delegate;
...
@end
@protocol SpriingDelegate
- (void)spriing:(Spriing*)aSpriing didFinishDownloadingString:(NSString*)aString;
@end
Spriing.m
中的
@implementation Spriing
@synthesize delegate;
...
//When its done
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
...
self.mStringData = [self processData:mStringData];
if ( self.delegate && [self.delegate respondsToSelector:@selector(spriing:didFinishDownloadingString:)]) {
[self.delegate spriing:self didFinishDownloadingString:self.mStringData];
}
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
...
@end
在视图控制器中,
- (void)viewDidLoad {
[super viewDidLoad];
spriing = [Spriing new];
spriing.delegate = self;
[spriing downloadData:@"http://www.spriing.co.uk/services/"];
}
- (void)spriing:(Spriing*)aSpriing didFinishDownloadingString:(NSString*)aString {
SpriingText.text = aString;
}
...