网络第一天:webView/多线程

1.webView加载网站

类名:UIWebView

实现方法如下:

(1)创建一个NSURL

NSURL *url = [NSURL URLWithString:@"http://www.tmooc.cn"];

创建一个NSURLRequest类型,就是用于从网络上请求数据的NSURLRequest *request = [NSURLRequest requestWithURL:url];

让我们创建的webView加载请求

[_webView loadRequest:request];

(4)一些常用方法

 //如果网址没有做移动端适配,那么屏幕显示不了全部的, 可以让网页自动缩放来适应

    _webView.scalesPageToFit = YES;

2.webView加载本地文件 

html文件的地址

NSString *path = [[NSBundle mainBundle] pathForResource:@"help" ofType:@"html"];

此处的pash是一个字符串,该字符串是一个地址,然后我们需要把该地址转换成URL格式.

(2)根据地址字符串转换成不同样式的文件,然后加载到webView上:

方法1:

NSURL *url = [NSURL fileURLWithPath:path];

注意此处用的是fileWithPath,而不能用URLWithString,这是获取本地文件跟网络文件的区别!!!!!!!

然后把该url发送给webView

[self.webView loadRequest:[NSURLRequest requestWithURL:url]]

方法2:

//** 称为二级指针,
     NSError *error = nil;
     //二级指针, 一般用于方法错误的抛出

下面的方法是直接把html文件转换成字符串,一个完整的字符串

 

NSString *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:&error];
     if (error) {
         NSLog(@"有错误 %@", error);
     }
     /*baseURL

     比如说一张图片的地址是http://www.baidu.com/111.jpg

     在html中一般写成<image>111.jgp<image>

     其中http://www.baidu.com前缀称为baseURL

     */

然后再把该字符串放到webView上

    //[self.webView loadHTMLString:content baseURL:nil];

方法3:

先转换成二进制数据,然后通过二进制数据加载到webView上

 NSData *data = [NSData dataWithContentsOfFile:path];

    [self.webView loadData:data MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:nil];

3.多线程

(1)几个概念

进程:(进行中的程序): 每个应用程序在启动起来以后, 就被称为一个进程, 表示他在CPU中占据了一席之地.进程中至少有一个线程, 这个基础的线程被称为主线程.

线程: 用于执行任务的,一个进程可以有多个线程, 通常称为主线程 和 子线程.

规定: 主线程上的任务优先于子线程上的任务执行.每一个线程, 同一时间只能做一件事. 多个任务需要排队执行.

用户可见的,可以感受的操作(UI操作)必须放在主线程中执行, 优先级最高. 非用户可见的操作, 最好不要放到主线程中执行了. 开辟子线程去执行.

关于线程的释放:线程在执行完内部任务以后, 会自动被注销, 释放掉.

管理线程的方式:

1>. pThread : 纯C的, 跨平台. 对于iOS没有优化.

2>.NSThread: 是使用OC对pThread的封装. 早期使用

3>.GCD: C语言, block语法. 对于iOS的多核操作有优化, 对线程处理最专业的方式. 现在的主流

4>.NSOperation: 使用OC语法封装了GCD, 并且额外加了几个功能点.

(2)NSThread

thread(线程)

这种方法需要把执行的操作写到一个方法里面,然后使用使用NSThread提供的方法把自定义的方法放到主线程或者子线程中去.

<1>使用NSThread提供的类别, 来把某个方法的执行放到子线程里

[self performSelectorInBackground:@selector(wasteTime) withObject:nil];

如果想把他放到主线程中,代码如下:

  [self performSelectorOnMainThread:@selector(changeTitle) withObject:nil waitUntilDone:NO];

最后一个参数是表示所选择的方法执行完了之后执行还是不等待直接执行.如果是NO代表不等待,直接执行下方的代码.

<2> 使用NSThread的类工厂方法开线程,开出来的线程是子线程

[NSThread detachNewThreadSelector:@selector(wasteTime) toTarget:self withObject:nil];

<3>该方法定制性最强,能设置线程的name

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(wasteTime) object:nil];
     //设置线程名称
     thread.name = @"嘻嘻";
     //设置此线程的优先级
     /*优先级排列右 高 -> 低

     NSQualityOfServiceUserInteractive:和用户交互有关系的任务, 例如滚动, 动画, 点击按钮~~

     NSQualityOfServiceUserInitiated: 用户请求的任务, 但是不需要精确处理. 例如用户在消息列表中点击查看某个邮件.

     NSQualityOfServiceUtility: 周期性的用户请求任务, 比如每5分钟刷新一次邮箱. 用户基本不能察觉. 多一次少一次无所谓.

     NSQualityOfServiceBackground: 一些后台优化, 电子邮件App对邮件进行索引以方便搜索.

     NSQualityOfServiceDefault:处于2和3之前的优先级.

  

*/
     thread.qualityOfService = NSQualityOfServiceDefault;
     
     //启动线程, 需要手动开启
     [thread start];

(3)GCD全称是Grand Central Dispatch,可译为“牛逼的中枢调度器”,GCD是纯C语言的,因此我们在编写GCD相关代码的时候,面对的函数,而不是方法。



一共是四种:异步串行,异步并行,同步串行,同步并行

我的理解是同步异步是决定了执行该任务是否可以开启新的线程,同步的话说明不可以开启新的线程,只能在当前线程下执行,而异步则说明可以开启新的线程。

串行跟并行是修饰队列的,串行队列是任务一个接着一个拍好顺序,等着线程来执行,而并行队列是多个任务并排,等着线程来执行,并行队列只有在异步才有效,因为它需要开辟多个线程来执行。

打个比方,异步就相当于有多扇门的公交车,乘客可以排一条队上车,这好比异步串行。乘客排多条对上车,就好比异步并行。

同步就好比只有一扇门的公交车,乘客只能排一条对上车,这是同步串行,如果排多条道上车,这就是同步并行,但是效果是只能串行上车。

<1>手动创建队列

创建串行队列并添加异步任务:(异步串行)

 dispatch_queue_t queue = dispatch_queue_create("Serial", DISPATCH_QUEUE_SERIAL);

队列创建好以后就可以往队列里添加任务了:(异步串行)

添加异步任务


dispatch_async(queue, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"%d, %@", i , [NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 'A'; i <= 'Z'; i++) {
            NSLog(@"%c, %@", i, [NSThread currentThread]);
        }
    });




创建并行队列并添加异步任务:(异步并行)

dispatch_queue_t queue = dispatch_queue_create("Concurrent", DISPATCH_QUEUE_CONCURRENT);
  dispatch_async(queue, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"%d, %@", i , [NSThread currentThread]);
        }
    });
    
    dispatch_async(queue, ^{
        for (int i = 'A'; i <= 'Z'; i++) {
            NSLog(@"%c, %@", i, [NSThread currentThread]);
        }
    });



串行队列中添加同步任务(同步串行)

 

dispatch_queue_t queue = dispatch_queue_create("Serial", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"%d, %@", i , [NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 'A'; i <= 'Z'; i++) {
            NSLog(@"%c, %@", i, [NSThread currentThread]);
        }
    });

创建并行队列并添加同步任务(同步并行)

dispatch_queue_t queue = dispatch_queue_create("Concurrent", DISPATCH_QUEUE_CONCURRENT);
     //2. 使用同步的方式, 添加打印0~9的方法到并行队列中
    dispatch_sync(queue, ^{
        for (int i = 0; i < 10; i++) {
            NSLog(@"%d, %@", i , [NSThread currentThread]);
        }
    });
     //3. 使用同步的方式, 添加打印A~Z的方法到并行队列中
    dispatch_sync(queue, ^{
        for (int i = 'A'; i <= 'Z'; i++) {
            NSLog(@"%c, %@", i, [NSThread currentThread]);
        }
    });

<2>使用系统自带的队列

你只需要获取它的指针

全局并行队列:


dispatch_queue_t
  queue = 
dispatch_get_global_queue 
( 
QOS_CLASS_DEFAULT 
,  
0 
);


注意这个队列是个并行队列。


主队列:


dispatch_queue_t mainQueue = dispatch_get_main_queue();
        dispatch_async(mainQueue, ^{
            self.view.backgroundColor = [UIColor greenColor];
        });

这是主线程

常见的锁死:

dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"------");
    });