iOS学习笔记13-网络(二)NSURLSession

在2013年WWDC上苹果揭开了NSURLSession的面纱,将它作为NSURLConnection的继任者。现在使用最广泛的第三方网络框架:AFNetworking、SDWebImage等等都使用了NSURLSession。作为iOS开发人员,应该紧随苹果的步伐,不断的学习,无论是软件的更新、系统的更新、API的更新,而不能墨守成规。

  • 相比较NSURLConnection,NSURLSession提供了 配置会话缓存、协议、cookie和证书能力,这使得网络架构和应用程序可以独立工作、互不干扰。
  • 另外,NSURLSession另一个重要的部分是 会话任务,它负责加载数据,在客户端和服务器端进行文件的上传下载。

下面让我们正式进入NSURLSession学习。

一、NSURLSession介绍

在NSURLSession时代,网络请求基本上由3个任务完成:
  • NSURLSessionData:请求数据任务
  • NSURLSessionUploadTask:请求上传任务
  • NSURLSessionDownloadTask:请求下载任务
关系图如下:

NSURLSessionTask支持任务的暂停、取消和恢复,并且默认任务运行在其他非主线程中

二、NSURLSession使用

说了这么多,是时候来露两手了,具体NSURLSession怎么用呢?

1. 数据请求

先看一个网络数据请求实例,和上一章的NSURLConnection请求对比参考:
- (void)loadJsonData{
    //1.创建url
    NSString *urlStr = @"http://192.168.1.208/ViewStatus.aspx?userName=KenshinCui&password=123";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    //2.创建请求
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //3.创建会话(这里使用了一个全局会话)
    NSURLSession *session = [NSURLSession sharedSession];
    //4.通过会话创建任务
    NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",dataStr);
        }else{
            NSLog(@"error is :%@",error.localizedDescription);
        }
    }];
    //5.每一个任务默认都是挂起的,需要调用 resume 方法启动任务
    [dataTask resume];
}

不难发现NSURLSession网络请求的五步走黄金油战略

  1. 创建NSURL
  2. 创建NSURLRequest
  3. 创建会话NSURLSession
  4. 通过会话创建任务NSURLSessionTask的子类
  5. 调用resume方法,启动任务

2. 文件下载

文件下载也是一样的,只是换上下载任务NSURLSessionDownloadTask就行,对回调做不同处理,一切都要贯彻五步走战略,O(∩_∩)O哈!

常用的创建文件下载任务的方法如下:
/* 回调类型,这是我为了排版方便抽出来的,实际框架中没有 */
typedef void (^downloadCompletionBlock)(NSURL*,NSURLReponse*,NSError*);
/* 创建文件下载任务,需要请求NSURLRequest */
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
                                    completionHandler:(downloadCompletionBlock)completion;
/* 创建文件任务,简化了一些操作,只需要URL就能进行文件下载 */
- (NSURLSessionDownloadTask *)downloadTaskWithURL:(NSURL *)url
                                completionHandler:(downloadCompletionBlock)completion;
下面是下载实例
-(void)downloadFile{
    //1.创建url
    NSString *fileName = @"1.jpg";
    NSString *urlStr = [NSString stringWithFormat: @"http://192.168.1.208/FileDownload.aspx?file=%@",fileName];
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    //2.创建请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    //3.创建会话(这里使用了一个全局会话)
    NSURLSession *session = [NSURLSession sharedSession];
    //4.创建文件下载任务
    NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request
          completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        if (!error) {
            //注意location是下载后的临时保存路径,需要将它移动到需要保存的位置
            NSError *saveError;
            NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
            NSString *savePath = [cachePath stringByAppendingPathComponent:fileName];
            NSURL *saveUrl = [NSURL fileURLWithPath:savePath];
            [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&saveError];
            if (!saveError) {
                NSLog(@"save sucess.");
            }
        }
    }];
    //5.启动任务
    [downloadTask resume];
}
  • 回调中的location是下载后的临时保存路径,需要将它移动到需要保存的位置
  • NSFileManager的对象方法
    ```objc
    //将fromURL路径下的文件拷贝到toURL路径下
  • (void)copyItemAtURL:(NSURL )fromUrl
    toURL:(NSURL 
    )toUrl
    error:(NSError **)error;
    ```

3.文件上传

使用NSURLConnection的文件上传时,我们还需要自己构建上传请求,主要是拼接上传表单,这是个十分麻烦的过程。
现在使用NSURLSessionUploadTask文件上传任务,我们就可以解放了,简单粗暴。
\(^o^)/~

下面是常用的创建上传任务的方法:
/* 回调类型,这是我为了排版方便抽出来的,实际框架中没有 */
typedef void (^UploadCompletionBlock)(NSData*,NSURLReponse*,NSError*);
/* 创建上传任务,需要提供上传文件二进制数据 */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromData:(NSData *)bodyData
                                completionHandler:(UploadCompletionBlock)completion;
/* 创建上传任务,需要提供上传文件所在的URL路径,不过这个方法常配合“PUT”请求使用 */
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
                                         fromFile:(NSURL *)fillURL
                                completionHandler:(UploadCompletionBlock)completion;
下面是上传实例:
- (void) NSURLSessionBinaryUploadTaskTest {
    // 1.创建url,采用Apache本地服务器进行测试
    NSString *urlStr = @"http://localhost/upload.php";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    // 2.创建请求,这里要设置POST请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";// 文件上传使用post
    // 3.获取全局会话Session
    NSURLSession *session = [NSURLSession sharedSession];
    // 4.创建上传任务,Request的Body Data将被忽略,而由fromData提供
    NSData *data = [NSData dataWithContentsOfFile:@"/Users/userName/Desktop/IMG_0359.jpg"];
    NSURLSessionUploadTask *upload =
           [session uploadTaskWithRequest:request
                                 fromData:data
                        completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (error == nil) {
            NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"upload success:%@",result);
        } else {
            NSLog(@"upload error:%@",error);
        }
    }]
    // 5.启动任务
    [upload resume];
}

是不是很简单,数据请求、文件下载、文件上传基本上都差不多,使用起来比NSURLConnection方便多了,还有什么理由不用NSURLSession呢!!

4.用dataTask上传文件【闲得蛋疼可以试一下】

除了上面的上传方式,实际上你也可以用NSURLSessionDataTask的方式上传,不过你就要自己设置上传BodyData和Header了,具体构建细节可以参考iOS学习笔记12-网络请求(一)NSURLConnection里面的构建过程,这里给个参考吧:

#pragma mark 上传文件
-(void)uploadFile{
    NSString *fileName = @"pic.jpg";
    //1.创建url
    NSString *urlStr = @"http://192.168.1.208/FileUpload.aspx";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    //2.创建请求
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    request.HTTPMethod = @"POST";
    //3.构建上传表单数据
    //设置数据体
    NSData *data = [self getHttpBody:fileName];
    request.HTTPBody = data;
    //设置请求头
    NSString *lengthStr = [NSString stringWithFormat:@"%lu",(unsigned long)data.length];
    [request setValue:lengthStr forHTTPHeaderField:@"Content-Length"];
    NSString *typeStr = [NSString stringWithFormat:@"multipart/form-data; boundary=%@",kBOUNDARY_STRING];
    [request setValue:typeStr forHTTPHeaderField:@"Content-Type"];
    //4.创建会话
    NSURLSession *session = [NSURLSession sharedSession];
    //5.创建dataTask任务,去做上传的功能
    NSURLSessionDataTask *uploadTask = [session dataTaskWithRequest:request
                                 completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        if (!error) {
            NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            NSLog(@"%@",dataStr);
        }else{
            NSLog(@"error is :%@",error.localizedDescription);
        }
    }];
    //6.启动任务
    [uploadTask resume];
}
上面的获取数据体方法getHttpBody,我也贴过来了
#pragma mark 取得数据体
-(NSData *)getHttpBody:(NSString *)fileName{
    NSMutableData *dataM = [NSMutableData data];
    NSString *type = [self getMIMETypes:fileName];
    //构建请求体body的顶部
    NSMutableString *bodyTop = [NSMutableString string];
    //宏kBOUNDARY_STRING就是boundary标示
    [bodyTop appendFormat:@"--%@\n",kBOUNDARY_STRING];
    [bodyTop appendFormat:@"Content-Disposition: form-data; name=\"file1\"; filename=\"%@\"\n",fileName];
    [bodyTop appendFormat:@"Content-Type: %@\n\n",type];
    //构建请求体body的底部
    NSString *bodyBottom = [NSString stringWithFormat:@"\n--%@--",kBOUNDARY_STRING];
    NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:nil];
    //构建请求体body中间的二进制上传数据
    NSData *fileData = [NSData dataWithContentsOfFile:filePath];
    //把顶部、数据、底部组合起来,形成body
    [dataM appendData:[bodyTop dataUsingEncoding:NSUTF8StringEncoding]];
    [dataM appendData:fileData];
    [dataM appendData:[bodyBottom dataUsingEncoding:NSUTF8StringEncoding]];
    return dataM;
}

三、会话Session控制

上面我们都是使用的全局NSURLSession,一般情况下我们就够用,但如果遇到两个连接使用不同的资源配置的情况,怎么办?答案就是自己定制。

  • NSURLSession支持我们自己定制NSURLSession
  • NSURLSession支持的三种会话配置:
  1. defaultSessionConfiguration
    进程内会话(默认会话),用硬盘来缓存数据。
  2. ephemeralSessionConfiguration
    临时的进程内会话(内存),不会将cookie、缓存储存到本地,只会放到内存中,当应用程序退出后数据也会消失。
  3. backgroundSessionConfiguration
    后台会话,相比默认会话,该会话会在后台开启一个线程进行网络数据处理。
下面就是定制NSURLSession的过程:
//使用默认会话配置
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.timeoutIntervalForRequest = 5.0f;//请求超时时间
sessionConfig.allowsCellularAccess = true;//是否允许蜂窝网络下载(2G/3G/4G)
//创建会话,指定配置和代理
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig
                                                      delegate:self
                                                 delegateQueue:nil];
上面设置了代理,NSURLSession有很多代理协议:
  • NSURLSessionDelegateNSObject
    会话父协议
  • NSURLSessionTaskDelegateNSURLSessionDelegate
    任务协议
  • NSURLSessionDataDelegateNSURLSessionTaskDelegate
    数据协议
  • NSURLSessionDownloadDelegate: NSURLSessionTaskDelegate
    下载协议
  • NSURLSessionStreamDelegateNSURLSessionTaskDelegate
    网络流协议
下面就拿最常用的下载协议NSURLSessionDownloadDelegate来讲下:
/* 下载中(会多次调用,可以记录下载进度) */
- (void)URLSession:(NSURLSession *)session
               downloadTask:(NSURLSessionDownloadTask *)downloadTask /* 下载任务 */
               didWriteData:(int64_t)bytesWritten /* 这次下载完成的字节数 */
          totalBytesWritten:(int64_t)totalBytesWritten /* 已经下载完成的总字节数 */
  totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite; /* 需要下载完成的总字节数 */

/* 成功下载完成 */
-(void)URLSession:(NSURLSession *)session
                 downloadTask:(NSURLSessionDownloadTask *)downloadTask /* 下载任务 */
    didFinishDownloadingToURL:(NSURL *)location;/* 下载完成后临时存放的URL */

/* 任务完成,不管是否下载成功 */
-(void)URLSession:(NSURLSession *)session
                    task:(NSURLSessionTask *)task /* 下载任务 */
    didCompleteWithError:(NSError *)error;/* 错误 */
实际上NSURLSessionTask任务除了resume启动之外,还有一些方法
/* 取消任务 */
- (void)cancel;
/* 挂起任务(暂停任务) */
- (void)suspend;
/* 启动任务 */
- (void)resume;
下面来个代码总结:
-(void)downloadFile{
    NSString *fileName = _textField.text;
    NSString *urlStr = [NSString stringWithFormat: @"http://192.168.1.208/FileDownload.aspx?file=%@",fileName];
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfig.timeoutIntervalForRequest = 5.0f;//请求超时时间
    sessionConfig.allowsCellularAccess = true;//是否允许蜂窝网络下载(2G/3G/4G)
    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfig
                                                          delegate:self
                                                     delegateQueue:nil];
    _downloadTask = [session downloadTaskWithRequest:request];
    [_downloadTask resume];
}
#pragma mark 点击取消下载
-(void)cancelDownload{
    [_downloadTask cancel];
}
#pragma mark 点击挂起下载
-(void)suspendDownload{
    [_downloadTask suspend];
}
#pragma mark 点击恢复下载
-(void)resumeDownload{
    [_downloadTask resume];
}
#pragma mark - 下载任务代理
#pragma mark 下载中(会多次调用,可以记录下载进度)
-(void)URLSession:(NSURLSession *)session
                downloadTask:(NSURLSessionDownloadTask *)downloadTask
                didWriteData:(int64_t)bytesWritten
           totalBytesWritten:(int64_t)totalBytesWritten
   totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    [self setUIStatus:totalBytesWritten expectedToWrite:totalBytesExpectedToWrite];//设置界面状态
}
#pragma mark 下载完成
-(void)URLSession:(NSURLSession *)session
                   downloadTask:(NSURLSessionDownloadTask *)downloadTask
      didFinishDownloadingToURL:(NSURL *)location
{
    NSError *error;
    NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath = [cachePath stringByAppendingPathComponent:_textField.text];
    NSURL *saveUrl = [NSURL fileURLWithPath:savePath];
    [[NSFileManager defaultManager] copyItemAtURL:location toURL:saveUrl error:&error];
}
#pragma mark 任务完成,不管是否下载成功
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
                          didCompleteWithError:(NSError *)error
{
    [self setUIStatus:0 expectedToWrite:0];//设置界面状态
}

四、Session后台开启任务

NSURLSession支持程序的后台下载和上传,苹果官方将其称为进程之外的上传和下载,这些任务都是交给后台守护线程完成的,而非应用程序本身。
即使文件在下载和上传过程中崩溃了也可以继续运行(注意如果用户强制退关闭应用程序,NSURLSession会断开连接)。

我们先来看下如何创建一个后台Session
#pragma mark 取得一个后台会话(保证一个后台会话,这通常很有必要,这里采用单例模式的形式)
- (NSURLSession *)backgroundSession{
    static NSURLSession *session = nil;
    static dispatch_once_t token;//下面代码块只执行一次,以后都不执行
    dispatch_once(&token, ^{
        NSStirng *identifier = @"com.cmjstudio.URLSession";
        NSURLSessionConfiguration *sessionConfig =
              [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier];
        sessionConfig.timeoutIntervalForRequest = 5.0f;//请求超时时间
        sessionConfig.discretionary = YES;//系统自动选择最佳网络下载
        sessionConfig.HTTPMaximumConnectionsPerHost = 5;//限制每次最多5个连接
        //创建会话
        session = [NSURLSession sessionWithConfiguration:sessionConfig
                                                delegate:self
                                           delegateQueue:nil];
    });
    return session;
}

然后我们拿到这个后台Session就可以做上面我们讲的下载和上传任务了。

我们来了解下程序进入后台后,任务是如何调度的,先上图:

当程序进入后台后,事实上任务是交给iOS系统来调度的,具体什么时候下载完成就不得而知,例如有个较大的文件经过一个小时下载完了,正常打开应用程序看到的此文件下载进度应该在100%的位置,但是由于程序已经在后台无法更新程序UI,而此时可以通过应用程序代理方法进行UI更新。

在AppDelegate.m中添加以下函数:
/*
    有其中几个任务完成后,系统会调用此应用程序的该方法
    此方法会包含一个competionHandler,通常我们会保存此对象
    competionHandler此操作表示应用完成所有处理工作
*/
- (void)application:(UIApplication *)application
        handleEventsForBackgroundURLSession:(NSString *)identifier
                          completionHandler:(void (^)())completionHandler
{
    //backgroundSessionCompletionHandler是自定义的一个属性
    self.backgroundSessionCompletionHandler = completionHandler;
}
在XXSession.m文件中实现NSURLSessionDelegate代理方法:
/*
    直到最后一个任务完成,系统会调用该方法。
    在这个方法中通常可以进行UI更新,并调用completionHandler通知系统已经完成所有操作。
*/
- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
{
    AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];

    //这中间就可以写更新UI的代码了,code

    if (appDelegate.backgroundSessionCompletionHandler) {
        void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler;
        appDelegate.backgroundSessionCompletionHandler = nil;
        completionHandler();
    }
}
时间: 2024-08-08 11:55:41

iOS学习笔记13-网络(二)NSURLSession的相关文章

iOS学习笔记20-地图(二)MapKit框架

一.地图开发介绍 从iOS6.0开始地图数据不再由谷歌驱动,而是改用自家地图,当然在国内它的数据是由高德地图提供的. 在iOS中进行地图开发主要有三种方式: 利用MapKit框架进行地图开发,利用这种方式可以对地图进行精准的控制 调用苹果官方自带的地图应用,主要用于一些简单的地图应用,无法精确控制 使用第三方地图开发SDK库 用得最多的还是MapKit,所以这节就只讲MapKit的使用. 二.MapKit核心类 MapKit的核心类为地图展示控件MKMapView,以下是常用的属性.对象方法以及

python 3.x 学习笔记13 (网络编程socket)

1.协议http.smtp.dns.ftp.ssh.snmp.icmp.dhcp....等具体自查 2.OSI七层应用.表示.会话.传输.网络.数据链路.物理 3.socket: 对所有上层协议的封装 4.socket常用功能1)sk.bind(address) s.bind(address) 将套接字绑定到地址.address地址的格式取决于地址族.在AF_INET下,以元组(host,port)的形式表示地址. 2)sk.listen(backlog) 开始监听传入连接.backlog指定在

IOS学习笔记 -- 网络编程

一.HTTP协议1.面试题: 聊一下HTTP协议(表达对HTTP协议的看法)* HTTP协议的全称: 超文本传输协议, 定制传输数据的规范(客户端和服务器之间的数据传输规范)* 描述HTTP协议完整的通信过程 2.通信过程1> 请求* 客户端 --> 服务器* 请求的内容a."请求行" : 请求方法\请求资源路径\HTTP协议版本GET /MJServer/login?username=123&pwd=123&method=get&type=JSON

iOS学习笔记---网络请求

一.HTTP协议的概念 HTTP协议:Hyper Text Transfer Protocol(超文本传输协议)是用于从万维网服务器传送超文本到本地浏览器的传输协议.HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型(c/s) HTTP协议的特点 支持客户/服务器模式(c/s模式) 简单快速 灵活,HTTP允许任意类型的对象进行传输,正在传输的对象类型由Content-type加以标记 iOS学习笔记---网络请求

iOS学习笔记-精华整理

iOS学习笔记总结整理 一.内存管理情况 1- autorelease,当用户的代码在持续运行时,自动释放池是不会被销毁的,这段时间内用户可以安全地使用自动释放的对象.当用户的代码运行告一段 落,开始等待用户的操作,自动释放池就会被释放掉(调用dealloc),池中的对象都会收到一个release,有可能会因此被销毁. 2-成员属性:     readonly:不指定readonly,默认合成getter和setter方法.外界毫不关心的成员,则不要设置任何属性,这样封装能增加代码的独立性和安全

iOS学习笔记22-推送通知

一.推送通知 推送通知就是向用户推送一条信息来通知用户某件事件,可以在应用退到后台后,或者关闭后,能够通过推送一条消息通知用户某件事情,比如版本更新等等. 推送通知的常用应用场景: 一些任务管理APP,会到任务时间即将到达时,通知你该做任务了. 健身APP定时提醒你应该健身了. 买过电影票,提前半个小时通知你,电影即将开场. 当你QQ或微信收到信息时,即使退到后台,也可以收到信息通知你. 电商APP,推送一条消息通知我们有新品上架等等. 推送通知的常用展示样式: 屏幕顶部显示一块横幅 在锁屏界面

IOS学习笔记---C语言第四天

1 //?生成2个数组,每个数组都有10个元素,元素取值范围20-40之间,数组对应元素相 加,放到另外?一个数组中 2 #import <Foundation/Foundation.h> 3 4 int main(int argc, const char * argv[]) 5 { 6 7 int num1[10]={0},num2[10]={0},num3[10]={0}; 8 for (int i = 0; i<10; i++) { 9 num1[i]=arc4random()%2

iOS: 学习笔记, 使用performSelectorOnMainThread及时刷新UIImageView

在iOS中, 界面刷新在主线程中进行, 这导致NSURLSession远程下载图片使用UIImageView直接设置Image并不能及时刷新界面. 下面的代码演示了如何使用 performSelectorOnMainThread: withObject:  waitUntilDone: 方法来及时刷新图片 1. 创建iOS空应用程序(Empty Application). 2. 加入一个控制器类. 在YYAppDelegate.m中修改 #import "MainViewController.h

黑马程序员--IOS学习笔记--数组及排序

IOS学习笔记 概述: 8_2.改变整型变量的符号 8_2.改变整型变量所占存储空间 8_3.char类型数据存储 8_4.数组的基本概念及分类 8_5.数组元素作为函数参数 8_5.一维数组定义及注意事项 8_6.一维数组初始化 8_7.一维数组一个让人疑惑的问题 8_8.一维数组的引用 8_9.应用:数组遍历 8_10.一维数组的存储方式 8_11.一维数组的地址 8_12.一维数组长度计算方法 8_13.一维数组的越界问题 8_14.应用:找最大值 8_15.数组元素作为函数参数 8_16