// // ViewController.h // 卖票 // // Created by apple on 13-7-29. // Copyright (c) 2013年 itcast. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController // 多行文本提示框 @property (weak, nonatomic) IBOutlet UITextView *infoTextView; // NSThread售票 - (IBAction)threadSales:(id)sender; // NSInvocationOperation售票 - (IBAction)invocationSales:(id)sender; // NSBlockOperation售票 - (IBAction)blockSales:(id)sender; // GCD售票 - (IBAction)gcdSales:(id)sender; @end
H:/0730/00_多线程4种售票_ViewController.m
<pre name="code" class="objc">
// ViewController.m // 卖票 // Created by apple on 13-7-29. #import "ViewController.h" @interface ViewController () { NSInteger _tickets; // 线程锁NSLock,必须是成员变量,不能是局部变量 NSLock *_lock; } // 下面的atomic成员,结合同步代码块使用,@synchronized (self) {} @property (assign, atomic) NSInteger tickets; /* 1. 在做多线程NSOperation和GCD技术的时候,抢夺的内存资源必须是“原子属性”——atomic 2. 抢夺的资源在使用的时候, //一定要用属性的self.xxx或者object.xxx,这样才getter,才atomic发挥作用 3. 要在Operation和GCD中抢夺资源,需要使用到“同步锁”,@synchronized(self){...} //目的是,锁住与抢夺资源相关的代码,包括读和写 4. 平时,尽量不要用抢夺资源去做判断条件,并且同步锁的范围越小越好! */ @end @implementation ViewController /* // 同步锁是要手敲出来的 @synchronized (self) { } */ // 为了在TextView里面增加文本,更新界面,需要先写一个方法处理。 // 1. 读出当前文本框的内容 // 2. 把要追加的文本附加在当前文本框内容的后面 // 3. 重新为文本框赋值 // 这是负责更新界面的UI - (void)appendTextView:(NSString *)text { NSMutableString *str = [NSMutableString stringWithString:_infoTextView.text]; [str appendFormat:@"\n%@", text]; [_infoTextView setText:str]; // 定义一个NSRange,代表文本框需要滚动到的位置 NSRange range = NSMakeRange(str.length, 1); // 我们现在想要滚动到最后,这个方法的参数是一个NSRange [_infoTextView scrollRangeToVisible:range]; } // 多线程一:响应按钮点击,启动NSThread售票 - (IBAction)threadSales:(id)sender { _tickets = 100; // 创建线程 NSThread1 NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil]; // 设置线程1的名字 [thread1 setName:@"售票线程-1"]; // 启动线程 NSThread1 只有NSThread需要手动start [thread1 start]; // 创建线程 NSThread2 NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil]; // 设置线程2的名字 [thread2 setName:@"售票线程-2"]; // 启动线程 NSThread2 只有NSThread需要手动start [thread2 start]; } // 多线程一:实际NSThread售票运行的代码,线程跑的方法 #pragma mark - 自定义方法,NSThread售票核心代码 - (void)threadSaleMethod { // 1. 判断是否还有票 // 2. 更新界面,提示当前票数 // 3. 总票数-1 // 4. 模拟延时 // 要解决一个问题:在threadSaleMethod这一个方法里面,我们就把所有的票卖光!!! // 线程锁:所谓线程锁,就是:在修改或者判断共享资源的时候, //需要把共享资源加锁,防止别的线程对 // 共享资源进行修改。 // 使用线程锁的方式: // 1. 定义锁,懒加载,且锁必须是成员变量 if (_lock == nil) { _lock = [[NSLock alloc]init]; } while (YES) { // 2. 使用共享资源之前,加锁 [_lock lock]; if (_tickets > 0) { // 做了一个字符串,显示提示信息 NSString *str = [NSString stringWithFormat:@"当前票数是%d,售票线程是%@", _tickets, [[NSThread currentThread]name]]; // 主线程,UI界面中显示一下票数 // 在多线程方法里面不能这样使用的 // [self appendTextView:@"12"]; // waitUntilDone 的意思是:是否等待主线程更新完毕 [self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES]; // 售完一张,票数减1 _tickets--; // 3. 使用共享资源完毕,立即解锁 [_lock unlock]; // 模拟不同售票效率 if ([[[NSThread currentThread]name] isEqualToString:@"售票线程-1"]) { [NSThread sleepForTimeInterval:0.2]; } else { [NSThread sleepForTimeInterval:0.3]; } } else { // 3. 使用共享资源完毕,立即解锁 [_lock unlock]; // 结束时,打印下线程名 NSString *str = [NSString stringWithFormat:@"票已售完%@", [[NSThread currentThread]name]]; // 主线程,UI界面中显示一下哪个线程结束了 [self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES]; NSLog(@"%@", str); // 退出循环 break; } } } // 多线程二:响应按钮点击,通过NSInvocationOperation添加到NSOperationQueue售票 - (IBAction)invocationSales:(id)sender { _tickets = 20; // 1. 定义2个NSInvocationOperation操作 // 1.1. 操作需要调用一个target对象的selector方法,类似NSThread // 1.2. 第3个参数object代表:方法是可以接收参数的,且只能接收一个。 NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSaleMethod:) object:@"Operation - 1"]; NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationSaleMethod:) object:@"Operation - 2"]; // 2. 定义1个操作队列NSOperationQueue NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 3. 将2个操作逐一添加到操作队列,自动启动 [queue addOperation:operation1]; [queue addOperation:operation2]; } // 多线程二:通过NSInvocationOperation添加到NSOperationQueue售票运行的代码,线程跑的方法 // 同样也是多线程三:通过NSOperationQueue的block售票的核心代码,线程跑的方法 #pragma mark - NSOperation售票,使用@synchronized(self){} // NSOperation售票方法,参数是上面方法定义的操作名称 - (void)operationSaleMethod:(NSString *)operationName { // 卖票流程——在这一个方法里面,我们需要把所有的票卖光!!! // 1. 是否有票 // 2. 显示当前票数 // 3. 票数-1 // 4. 通过延时,模拟效率 while (YES) { // !!!同步锁要锁住所有抢夺资源的代码 // 平时,尽量不要用抢夺的资源做判断条件,会增加同步锁的范围,降低效率! @synchronized(self) { if (self.tickets > 0) { NSString *str = [NSString stringWithFormat:@"当前票数:%d,线程名称:%@", self.tickets, operationName]; // 主线程队列“只”负责更新UI // 把所有的成员变量调用的位置都改成了getter方式调用,发挥atomic关键字 // 属性调用是通过getter,这样调用才能发挥atomic的作用 [[NSOperationQueue mainQueue]addOperationWithBlock:^{ // 在NSOperationQueue的主队列中,只负责更新界面UI [self appendTextView:str]; }]; self.tickets--; // 通过延时,模拟不同售票效率 if ([operationName isEqualToString:@"Operation - 1"] || [operationName isEqualToString:@"Block - 1"]) { [NSThread sleepForTimeInterval:0.2]; } else { [NSThread sleepForTimeInterval:1.0]; } } else { NSString *str = [NSString stringWithFormat:@"票已售完,线程名称:%@", operationName]; // 在NSOperationQueue的主队列中,只负责更新界面UI [[NSOperationQueue mainQueue]addOperationWithBlock:^{ [self appendTextView:str]; }]; break; } }//同步代码块@synchronized,到这儿才结束 } } // 多线程三:响应按钮点击,通过NSOperationQueue的block售票 - (IBAction)blockSales:(id)sender { _tickets = 20; // 1,定义NSOperationQueue操作队列 NSOperationQueue *queue = [[NSOperationQueue alloc]init]; // 2,通过block给操作队列添加自定义方法,并执行 [queue addOperationWithBlock:^{ [self operationSaleMethod:@"Block - 1"]; }]; // 2,通过block给操作队列添加自定义方法,并执行 [queue addOperationWithBlock:^{ [self operationSaleMethod:@"Block - 2"]; }]; // 2,通过block给操作队列添加自定义方法,并执行 [queue addOperationWithBlock:^{ [self operationSaleMethod:@"Block - 3"]; }]; // 3,设置NSOperationQueue操作队列,最大并发执行任务个数 [queue setMaxConcurrentOperationCount:2]; } // 多线程四:响应按钮点击,通过GCD grand central dispatch售票 - (IBAction)gcdSales:(id)sender { _tickets = 20; // 1. 获取全局队列 dispatch_get_global_queue,参数1为默认优先级, // 参数2标记永远是0 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 2. 创建小组 dispatch_group_create dispatch_group_t group = dispatch_group_create(); // 3. 向小组添加异步任务一,dispatch_group_async // 参数1,小组名 // 参数2,全局队列名 // 参数3,block,即指定具体要执行的方法,可带参数:名字 dispatch_group_async(group, queue, ^{ [self gcdSaleMethod:@"GCD-1"]; }); // 3. 向小组添加异步任务二,dispatch_group_async // 参数1,小组名 // 参数2,全局队列名 // 参数3,block,即指定具体要执行的方法,可带参数,名字 dispatch_group_async(group, queue, ^{ [self gcdSaleMethod:@"GCD-2"]; }); // 4. 监听小组通知 // 参数1,小组名 // 参数2,获得主队列 dispatch_get_main_queue() // 参数3,block代码块:所有异步任务都完成时,要做的事情!!! dispatch_group_notify(group, dispatch_get_main_queue(), ^{ // 提示用户没有票了!更新到界面UI [self appendTextView:@"票已售完!"]; }); } // 多线程四:通过GCD向小组添加的异步任务,即线程跑的方法 #pragma mark - GCD售票 具体卖票流程 - (void)gcdSaleMethod:(NSString *)gcdName { // 1. 确认票数 // 2. 更新界面 // 3. 票数-1 // 4. 模拟延时 while (YES) { if (_tickets > 0) { // 1. 确定要更新的内容 NSString *str = [NSString stringWithFormat:@"当前票数:%d, 售票线程:%@", _tickets, gcdName]; // 2. dispatch_async(),开启异步任务, // 参数1,要在哪个地方执行该异步任务:dispatch_get_main_queue() // 参数2,block指明要执行的具体异步任务:更新UI界面,并且票数-1 dispatch_async(dispatch_get_main_queue(), ^{ [self appendTextView:str]; // GCD中 对共用资源的修改也要放到获得的主队列里 _tickets--; }); // 通过延时,模拟不同售票效率 if ([gcdName isEqualToString:@"GCD-1"]) { [NSThread sleepForTimeInterval:0.2]; } else { [NSThread sleepForTimeInterval:1.0]; } } else { break; } } } @end
H:/0730/01_ASI_ViewController.h
// ViewController.h // ASI演练 // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. #import <UIKit/UIKit.h> #import "ASIHTTPRequest.h" @interface ViewController : UIViewController <ASIHTTPRequestDelegate, ASIProgressDelegate> // 响应按钮点击,下载文件 - (IBAction)downloadFile:(id)sender; @end
H:/0730/01_ASI_ViewController.m
<pre name="code" class="objc">// ViewController.m // ASI演练 /* ASI工程注意事项: 1,不能选ARC 2,更改IOS 部署 目标为 IOS5.0 3,将ASI压缩包,解压,拖动Classes文件夹和External目录拖进工程 4,尝试编译,出现错误:无法找到libxml/HTMLparser.h 解决方法: 进入build settings,找到_head search paths头文件搜索目录_添加: ${SDK_DIR}/usr/include/libxml2,并回车 5,再次尝试编译,出现错误:ASITestCase.h:12:9: 'GHUnitIOS/GHUnit.h' file not found 错误原因:没有GHUnit框架 解决办法: 进入build phases 展开compile sources 将tests结尾的文件全部移除,按减号,即测试文件,不参与编译 即删除单元测试部分的代码引用 6,再次command B 编译,85个错误 解决方法: 很简单,进入summary,找到链接的框架和引用,+号,添加下列iOS框架引用即可 CFNetwork.framework SystemConfiguration.framework MobileCoreServices.framework libz.dylib libxml2.dylib 7,上述框架,在ASI提供的工程样本中可以看到,再次编译OK 8,为了解压缩,还要添加SSZipArchive框架 将以下文件加入工程: SSZipArchive.h SSZipArchive.m minizip文件夹 9,编译OK */ // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. #import "ViewController.h" #import "SSZipArchive.h" // 遵守两个ASI协议 <ASIHTTPRequestDelegate, ASIProgressDelegate> @interface ViewController () { // 下载文件的大小,头信息字典中的文件长度,在后面进度中要用到 CGFloat _fileLength; } @end @implementation ViewController #pragma mark - 响应按钮点击,开始启动ASI框架断点续传下载文件 - (IBAction)downloadFile:(id)sender { // 1. 指定下载文件地址 NSString *urlString = @"http://teacher.local/~apple/itcast/download/iTunesConnect_DeveloperGuide_CN.zip"; NSURL *url = [NSURL URLWithString:urlString]; // 2. 设定文件保存路径及临时缓存路径 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //保存路径 NSString *downloadPath = [documents[0]stringByAppendingPathComponent:@"book.zip"]; //缓存路径 NSString *tempPath = [documents[0]stringByAppendingPathComponent:@"book.tmp"]; // 3. 通过URL,初始化ASIHTTPRequest实例对象,不支持ARC ASIHTTPRequest *request = [[[ASIHTTPRequest alloc]initWithURL:url]autorelease]; // 4. 设置代理为当前控制器——ASI是通过代理回调的方式处理网络请求的 [request setDelegate:self]; // 5. 设置下载完毕的保存路径 [request setDownloadDestinationPath:downloadPath]; // 6. 设置临时缓存路径 [request setTemporaryFileDownloadPath:tempPath]; // 7. 设置允许断点续传 [request setAllowResumeForFileDownloads:YES]; // 8. 设置下载进程代理——用户想知道下载的实际进展情况 [request setDownloadProgressDelegate:self]; // 9. 启动异步请求 [request start]; } #pragma mark - ASI代理方法 // 2. 接收到响应头 didReceiveResponseHeaders 目的获得文件长度 - (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders { // 通过Log,我们看到了"Content-Length" = 6105204; // 貌似可以用来监控下载进度 // 暂时不去管它 NSLog(@"请求头%@", responseHeaders); // 在这里,我们能够知道文件长度,如果我们在这里记录下来文件的长度,假设100M // 需要获得的是文件的兆数会更加人性化 字节->K->M(1024) NSInteger length = [responseHeaders[@"Content-Length"]integerValue]; // 文件长度计算之后,是一个小数,需要改变一下成员变量的类型 _fileLength = (CGFloat)length / 1024 / 1024; } #pragma mark - 下载进度的代理方法 - (void)setProgress:(float)newProgress { // 传回来的参数是一个下载进度的百分比 // 那么,我们告诉用户还差多少M下载完成? NSLog(@"%.2f", newProgress * _fileLength); // 100M * 0.2 = 20M } #pragma mark - ASI代理方法 // 3. 请求完成 requestFinished - (void)requestFinished:(ASIHTTPRequest *)request { NSLog(@"请求完成"); // 我们可以去做解压缩的工作了。因为下载工作已经完成了! // 需求: // 1. 知道文件保存路径 // 2. 解压缩文件 // 2.1 定义一个压缩文件 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *downloadPath = [documents[0]stringByAppendingPathComponent:@"book.zip"]; // 2.3 调用SSZipArchive的类方法解压缩,参数2是一个目录 [SSZipArchive unzipFileAtPath:downloadPath toDestination:documents[0]]; // 3. 通过文件管理者(单例),删除压缩文件 [[NSFileManager defaultManager]removeItemAtPath:downloadPath error:nil]; } #pragma mark - ASI代理方法 // 代理方法之1. 请求开始 - (void)requestStarted:(ASIHTTPRequest *)request { NSLog(@"请求开始"); } #pragma mark - ASI代理方法 // 代理方法之4. 请求失败 - (void)requestFailed:(ASIHTTPRequest *)request { NSLog(@"请求失败"); } @end
H:/0730/02_AFN_ViewController.h
// // ViewController.h // AFN断点续传演练 // // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController // 下载文件 - (IBAction)downloadFiles:(id)sender; @end
H:/0730/02_AFN_ViewController.m
<pre name="code" class="objc">// ViewController.m // AFN断点续传演练 // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. /* AFN使用步骤: 1,新建工程的时候,勾选ARC(毕竟AFN有是人在维护的) 2,拖动文件夹AFNetworking到工程中 3,将解压要用到的文件夹SSZipArchive拖到工程中 同时导入它依赖的libz.dylib框架 4,编译,弹出2个warning,缺少框架 SystemConfiguration.framework MobileCoreServices.framework 5,展开supporting files文件夹,找到--> 工程名-Prefix.pch文件,在#endif的前面添加 #import<SystemConfiguration/SystemConfiguration.h> #import<MobileCoreServices/MobileCoreServices.h> 6,再次编译ok */ #import "ViewController.h" #import "AFNetworking.h" #import "SSZipArchive.h" @interface ViewController () @end @implementation ViewController #pragma mark - 下载文件 - (IBAction)downloadFiles:(id)sender { // 1. 指定下载文件地址 NSURL *url = [NSURL URLWithString:@"http://169.254.98.245/~apple/itcast/download/iTunesConnect_DeveloperGuide_CN.zip"]; // 2. 指定文件保存路径 NSArray *documents = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *downloadPath = [documents[0]stringByAppendingPathComponent:@"book.zip"]; // 3. 创建NSURLRequest NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 4. 通过固定请求,创建AFURLConnectionOperation,多态 AFURLConnectionOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; // 5. 设置操作的输出流(在网络中的数据是以流的方式传输的, //告诉操作把文件保存在第2步设置的路径中) [operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:downloadPath append:NO]]; // 6. 设置下载进程处理块代码 // 6.1 bytesRead 读取的字节——这一次下载的字节数 // 6.2 totalBytesRead 读取的总字节——已经下载完的 // 6.3 totalBytesExpectedToRead 希望读取的总字节——就是文件的总大小 [operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) { // 做下载进度百分比的工作 NSLog(@"下载百分比:%f", (float)totalBytesRead / totalBytesExpectedToRead); }]; // 7. 操作完成块代码 [operation setCompletionBlock:^{ // 解压缩的顺序 // 1. 定义要解压缩的文件 —— downloadPath // 2. 要解压缩的目标目录,必须是目录 // 3. 调用类方法解压缩 [SSZipArchive unzipFileAtPath:downloadPath toDestination:documents[0]]; // 使用文件管理者,删除压缩包 [[NSFileManager defaultManager]removeItemAtPath:downloadPath error:nil]; }]; // 8 启动操作 [operation start]; } @end
H:/0730/04_UIWebView_ViewController.h
// // ViewController.h // UIWebView演练 // // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController // 成员属性:UIWebView控件 @property (weak, nonatomic) IBOutlet UIWebView *localWebView; // 点击,加载PDF文件按钮 - (IBAction)clickPDFButton:(id)sender; // 点击,加载HTMLString - (IBAction)loadHTMLString:(id)sender; // 点击,使用loadData加载数据 - (IBAction)loadData:(id)sender; @end
H:/0730/04_UIWebView_ViewController.m
<pre name="code" class="objc">// ViewController.m // UIWebView演练 // Created by apple on 13-7-30. // Copyright (c) 2013年 itcast. All rights reserved. #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 通过自定义方法获得MIMETYPE [self mimeType]; } // 自定义方法,获取MIMEType // 因为我们不能记住所有类型文档的MIMEType,所以我们自己动手,写一个方法 - (NSString *)mimeType { // 一。本地文件URL生成的过程 // 1. 绝对路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"关于.docx" ofType:nil]; // 2 绝对路径转FILEURL NSURL *fileURL = [NSURL fileURLWithPath:path]; // 二。网络文件URL生成的过程 // 1. 网络地址字符串 NSString *urlString = @"http://www.baidu.com"; // 2. 生成URL NSURL *webURL = [NSURL URLWithString:urlString]; // 1. 定义固定请求 NSURLRequest *request = [NSURLRequest requestWithURL:fileURL]; // 2. 定义响应,到时候,传入地址,到时候方便接收返回的response NSURLResponse *response = nil; // 3. NSConnection静态方法,发送同步请求,传入接收响应的地址 [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]; NSLog(@"MIMEType %@", response.MIMEType); return response.MIMEType; } // 响应按钮点击事件, - (IBAction)clickPDFButton:(id)sender { [self viewLocalPDFFile]; } // 1. 我们现在准备了一个素材是PDF // 2. 我们要把这个PDF显示在webView里面 // 显示本地PDF文件在WebView - (void)viewLocalPDFFile { // 1. 定义URL // 1. 全路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"iTunesConnect_DeveloperGuide_CN.pdf" ofType:nil]; // 2 全路径得到fileURL NSURL *fileURL = [NSURL fileURLWithPath:path]; // 2. 通过fileURL构建请求 NSURLRequest *request = [NSURLRequest requestWithURL:fileURL]; // 4. 重要!!!!!!设置WebView的数据侦测类型:为侦测所有类型 [_localWebView setDataDetectorTypes:UIDataDetectorTypeAll]; // 5. 使用WebView加载这个请求即可 [_localWebView loadRequest:request]; } // 响应按钮点击,加载HTMLString - (IBAction)loadHTMLString:(id)sender { // 暂时不考虑baseURL,集中在String上面 // 用“iOS 正则表达式”去搜索相关知识点,可以做新闻类的应用! NSString *fullHTML = @"<html><head><title>hello</title></head><body><p1>我爱你</p1></body></html>"; NSString *partHTML = @"<p1>我爱你!!!</p1>"; // webview是可以显示部分html代码的 [_localWebView loadHTMLString:partHTML baseURL:nil]; } // 响应按钮点击,加载“data数据”——NSData - (IBAction)loadData:(id)sender { // 1. pdf文件绝对路径 NSString *path = [[NSBundle mainBundle]pathForResource:@"iTunesConnect_DeveloperGuide_CN.pdf" ofType:nil]; // 2 通过 绝对路径 生成fileURL NSURL *fileURL = [NSURL fileURLWithPath:path]; // 2. 用NSData类方法加载数据,参数为fileURL NSData *data = [NSData dataWithContentsOfURL:fileURL]; // 3. 使用webView加载data类型数据 [_localWebView loadData:data MIMEType:@"application/pdf" textEncodingName:@"UTF-8" baseURL:nil]; } @end
H:/0730/05_UIWebView浏览器综合应用_ViewController.h
// // ViewController.h // UIWebView Demo // // Created by apple on 13-7-21. // Copyright (c) 2013年 itcast. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController <UITextFieldDelegate, UIWebViewDelegate> // URL文本 @property (weak, nonatomic) IBOutlet UITextField *urlText; // 回退按钮 @property (weak, nonatomic) IBOutlet UIBarButtonItem *goBackButton; // 前进按钮 @property (weak, nonatomic) IBOutlet UIBarButtonItem *goForwardButton; // 重载按钮 @property (weak, nonatomic) IBOutlet UIBarButtonItem *reloadButton; // 停止按钮 @property (weak, nonatomic) IBOutlet UIBarButtonItem *stopButton; // Web视图 @property (weak, nonatomic) IBOutlet UIWebView *webView; // 回退 - (IBAction)goBack:(id)sender; // 前进 - (IBAction)goForward:(id)sender; // 刷新 - (IBAction)reloadURL:(id)sender; // 提交表单 - (IBAction)submit:(id)sender; @end
H:/0730/05_UIWebView浏览器综合应用_ViewController.m
// ViewController.m // UIWebView 浏览器综合演示 // Created by apple on 13-7-21. // Copyright (c) 2013年 itcast. All rights reserved. #import "ViewController.h" @interface ViewController () // 访问指定URL字符串的内容,仅由文本框回车事件调用 - (void)gotoURLString:(NSString *)urlString; // 访问指定的URL内容 - (void)gotoURL:(NSURL *)url; // 获得本地文件的MIMEType - (NSString *)MIMEType:(NSString *)fileName; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self MIMEType:@"001.网络基础.pdf"]; // 调用自定义测试方法 [self testLoadHTMLFile]; } // 测试加载本地HTML文件 - (void)testLoadHTMLFile { // 测试加载本地HTML文件,需要指定MIMETYPE NSString *dataPath = [[NSBundle mainBundle]pathForResource:@"demo.html" ofType:nil]; // baseURL基址,以便查找CSS JS jpg等 NSURL *baseURL = [NSURL fileURLWithPath:[[NSBundle mainBundle]resourcePath] isDirectory:YES]; // 只有加载的html文件才需要指定baseURL路径,告诉浏览器去哪里找图片、样式表等文件 [_webView loadData:[NSData dataWithContentsOfFile:dataPath] MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:baseURL]; } // 自定义方法,获得本地文件的MIMEType - (NSString *)MIMEType:(NSString *)fileName { // 根据文件名,得到绝对路径 NSString *path = [[NSBundle mainBundle]pathForResource:fileName ofType:nil]; // 根据绝对路径,得到fileURL NSURL *url = [NSURL fileURLWithPath:path]; // 根据url 创建固定请求 NSURLRequest *request = [NSURLRequest requestWithURL: url]; // 定义响应,以便接收响应内容 NSURLResponse *response = nil; // 发送同步请求,并传入响应的地址,以便接收响应 [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil]; NSLog(@"MIMEType is %@", [response MIMEType]); return [response MIMEType]; } #pragma mark - UIWebView加载内容的测试方法 // 加载HTML字符串 - (void)testLoadHTMLString { // 测试加载HTML字符串 NSString *html = @"<html><head><title>红楼梦</title></head><body><h1>世外仙姝</h1></body></html>"; [_webView loadHTMLString:html baseURL:nil]; } // 加载部分HTML字符串测试 - (void)testLoadPartHTMLString { // 测试加载部分HTML字符串,不需要显示整个网页内容时,通常使用此方法 NSString *partHtml = @"<h1>寂寞林</h1>"; [_webView loadHTMLString:partHtml baseURL:nil]; } // 加载本地PDF文件 - (void)testLoadPDFFile { // 测试加载本地PDF,需要指定MIMETYPE NSString *dataPath = [[NSBundle mainBundle]pathForResource:@"001.网络基础.pdf" ofType:nil]; [_webView loadData:[NSData dataWithContentsOfFile:dataPath] MIMEType:@"application/pdf" textEncodingName:@"UTF-8" baseURL:nil]; } // 加载本地文本文件 - (void)testLoadTextFile { // 测试加载本地文本文件,需要指定MIMETYPE NSString *dataPath = [[NSBundle mainBundle]pathForResource:@"关于.txt" ofType:nil]; [_webView loadData:[NSData dataWithContentsOfFile:dataPath] MIMEType:@"text/plain" textEncodingName:@"UTF-8" baseURL:nil]; } #pragma mark - UITextField代理方法 // 文本框回车事件 - (BOOL)textFieldShouldReturn:(UITextField *)textField { // 如果被回车的是地址栏,且不为空 if (textField == _urlText && textField.text.length > 0) { // 退出键盘 [textField resignFirstResponder]; // 调用自定义方法,转到URLstring方法 [self gotoURLString:textField.text]; } return YES; } #pragma mark - 自定义方法,回车后,调用访问指定URL内容 // 访问指定URL字符串的内容,仅由文本框事件调用,文本框回车时候调用的 - (void)gotoURLString:(NSString *)urlString { NSURL *url = nil; // 判断是否是httpURL if ([urlString hasPrefix:@"http://"]) { // URL中有中文的,是需要加百分号的! url = [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } else if ([urlString hasPrefix:@"file://"]) { // 判断给定参数是否已经是完整的url路径,避免出现前进后退后, //URL变成完整URL无法访问的情况 if ([urlString hasPrefix:@"file://localhost/"]) { // 注意此处不能使用fileURLWithPath方法??????????? // 因为fileURLWithPath是将绝对路径,转成fileURL // 而此时,已经是fileURL了 url = [NSURL URLWithString:urlString]; } else { // 如果没有localhost前缀的,说明是新输入的本地文件,需要转换url。 // 检测字串范围 NSRange range = [urlString rangeOfString:@"file://"]; // 截取剩余部分作为文件名 NSString *fileName = [urlString substringFromIndex:range.length]; // 根据文件名,生成文件绝对路径 NSString *path = [[NSBundle mainBundle]pathForResource:fileName ofType:nil]; // 判断绝对路径是否存在 if ([[NSFileManager defaultManager]fileExistsAtPath:path]) { // 若存在,将绝对路径转成fileURL url = [NSURL fileURLWithPath:path]; } else { url = nil; } } } // 如果到这儿url仍为空,说明,转换失败,输入地址栏内容有误 if (url == nil) { UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示" message:@"输入地址不正确,请重新输入!" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil, nil]; [alert show]; // 设置文本框输入焦点 [_urlText becomeFirstResponder]; } else { // 地址正确,下一步,调用自定义方法,访问指定的URL内容 [self gotoURL:url]; } } // 地址正确,下一步,调用自定义方法,访问指定的URL内容 - (void)gotoURL:(NSURL *)url { // 使用转换后的URL字符串替代用户输入的URL文本框内容 // absoluteString??? [_urlText setText:[url absoluteString]]; // 1, 根据url 创建固定请求 NSURLRequest *request = [NSURLRequest requestWithURL:url]; // 2, 设置浏览器,自动侦测所有数据类型 [_webView setDataDetectorTypes:UIDataDetectorTypeAll]; // 3, webView 加载请求 [_webView loadRequest:request]; } // 响应按钮点击,JS 提交表单 - (IBAction)submit:(id)sender { // 获取当前页面的url NSString *url = [_webView stringByEvaluatingJavaScriptFromString:@"document.location.href"]; NSLog(@"url %@", url); // 获取当前页面的标题 NSString *title = [_webView stringByEvaluatingJavaScriptFromString:@"document.title"]; NSLog(@"title %@", title); // 提交表单 [_webView stringByEvaluatingJavaScriptFromString:@"document.forms[0].submit(); "]; } #pragma mark - UIWebViewDelegate 代理方法 // 网页中的每一个请求都会被触发这个方法,返回NO代表不执行这个请求(常用于JS与iOS之间通讯) - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { NSLog(@"将要加载请求"); return YES; } #pragma mark - IBActions // 调用浏览器webView默认的,回退操作 - (IBAction)goBack:(id)sender { [_webView goBack]; } // 调用浏览器webView默认的,前进操作 - (IBAction)goForward:(id)sender { [_webView goForward]; } // 调用浏览器webView默认的,刷新操作 - (IBAction)reloadURL:(id)sender { [_webView reload]; } #pragma mark - UIWebViewDelegate 代理方法 // 网页开始加载的时候调用 - (void)webViewDidStartLoad:(UIWebView *)webView { NSLog(@"开始加载"); } #pragma mark - UIWebViewDelegate 代理方法 // 网页加载完成的时候调用 - (void)webViewDidFinishLoad:(UIWebView *)webView { NSLog(@"加载完成"); } #pragma mark - UIWebViewDelegate 代理方法 // 网页加载出错的时候调用 - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { NSLog(@"加载出错%@", [error localizedDescription]); } @end