iOS里线程可以使用四种方法,其优缺点以及介绍如下:
技术方案 | 简介 | 语言 | 线程管理 | 使用频率 |
---|---|---|---|---|
pthread | 一套通用的多线程API 适用于Unix\Linux\Windows等系统 跨平台\可移植 使用难度大 |
C | 程序员管理 | 几乎不用 |
NSThread | 使用更加面向对象 简单易用,可直接操作线程对象 |
OC | 程序员管理 | 偶尔使用 |
GCD | 旨在替代NSThread等线程技术 充分利用设备的多核 |
C | 自动管理 | 经常使用 |
NSOperation | 基于GCD(底层是GCD) 比GCD多了一些更简单实用的功能 使用更加面向对象 |
OC | 自动管理 | 经常使用 |
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];[thread start];
// 线程一启动,就会在线程thread中执行self的run方法[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
//创建线程后自动启动线程[self performSelectorInBackground:@selector(run) withObject:nil];
//隐式创建并启动线程后2种创建线程方式简单快捷但是无法对线程进行更详细的设置
主线程相关用法
+(NSThread *)mainThread; // 获得主线程
-(BOOL)isMainThread; // 是否为主线程
+(BOOL)isMainThread; // 是否为主线程
获得当前线程
NSThread *current = [NSThread currentThread];
线程的调度优先级
+(double)threadPriority;
+(BOOL)setThreadPriority:(double)p;
-(double)threadPriority;
-(BOOL)setThreadPriority:(double)p;
调度优先级的取值范围是0.0 ~ 1.0,默认0.5,值越大,优先级越高
线程的名字
-(void)setName:(NSString *)n;
-(NSString *)name;
线程状态一般分为:新建、就绪、运行、阻塞、死亡。
启动线程
- (void)start; // 进入就绪状态 -> 运行状态。当线程任务执行完毕,自动进入死亡状态
阻塞(暂停)线程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti; // 进入阻塞状态
强制停止线程
+ (void)exit; // 进入死亡状态
注意:一旦线程停止(死亡)了,就不能再次开启任务
使用锁可以避免多条线程抢夺同一块资源
@synchronized(锁对象)~~~~ {// 需要锁定的代码 }
一般都是锁self
GCD中有2个核心概念:任务:执行什么操作,队列:用来存放任务。
GCD的使用的2个步骤:定制任务(确定想做的事情),将任务添加到队列中(GCD会自动将队列中的任务取出,放到对应的线程中执行,任务的取出遵循队列的FIFO原则:先进先出,后进后出)
GCD中有2个用来执行任务的函数(同步和异步)
用同步的方式执行任务
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue:队列
block:任务
用异步的方式执行任务
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
同步、异步、并发、串行
同步和异步决定了要不要开启新的线程
同步:在当前线程中执行任务,不具备开启新线程的能力
异步:在新的线程中执行任务,具备开启新线程的能力
并发和串行决定了任务的执行方式
并发:多个任务并发(同时)执行
串行:一个任务执行完毕后,再执行下一个任务
GCD的队列可以分为2大类型
并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
并发功能只有在异步(dispatch_async)函数下才有效
串行队列(Serial Dispatch Queue)
让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)
并发队列的创建
GCD默认已经提供了全局的并发队列,供整个应用使用,不需要手动创建
使用dispatch_get_global_queue函数获得全局的并发队列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 队列的优先级
unsigned long flags); // 此参数暂时无用,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 获得全局并发队列
全局并发队列的优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默认(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后台
串行队列的创建
GCD中获得串行有2种途径
使用dispatch_queue_create函数创建串行队列
dispatch_queue_t
dispatch_queue_create(const char *label, // 队列名称
dispatch_queue_attr_t attr); // 队列属性,一般用NULL即可
dispatch_queue_t queue = dispatch_queue_create("cn.itcast.queue", NULL); // 创建
dispatch_release(queue); // 非ARC需要释放手动创建的队列
使用主队列(跟主线程相关联的队列)
dispatch_queue_t queue = dispatch_get_main_queue();
主队列是GCD自带的一种特殊的串行队列
放在主队列中的任务,都会放到主线程中执行
各种队列的执行效果
全局并发队列 | 手动创建串行队列 | 主队列 |
---|---|---|
同步(sync) | 没有开启新线程 串行执行任务 |
没有开启新线程 串行执行任务 |
异步(async) | 有开启新线程 并发执行任务 |
有开启新线程 串行执行任务 |
线程间通信
// 从子线程回到主线程
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
GCD的其他用法
执行延时
调用NSObject的方法
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 2秒后再调用self的run方法
使用GCD函数
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // 2秒后异步执行这里的代码...});
一次性代码
使用dispatch_once函数能保证某段代码在程序运行过程中只被执行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 只执行1次的代码(这里面默认是线程安全的)
});
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0), ^{
// 执行1个耗时的异步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的异步操作都执行完毕后,回到主线程...
});
ARC/MRC下单例模式的写法
可以用宏判断是否为ARC环境
#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif
ARC下:
// 在.m中保留一个全局的static的实例
static id _instance;
// 重写allocWithZone:方法,在这里创建唯一的实例(注意线程安全)
+ (id)allocWithZone:(struct _NSZone *)zone
{
@synchronized(self) {
if (!_instance) {
_instance = [super allocWithZone:zone];
}
}
return _instance;
}
// 提供1个类方法让外界访问唯一的实例
+ (instancetype)sharedSoundTool
{
@synchronized(self) {
if (!_instance) {
_instance = [[self alloc] init];
}
}
return _instance;
}
MRC下(比ARC多了几个步骤):
// 实现copyWithZone:方法
+ (id)copyWithZone:(struct _NSZone *)zone
{
return _instance;
}
// 实现内存管理方法
- (id)retain { return self; }
- (NSUInteger)retainCount { return 1; }
- (oneway void)release {}
- (id)autorelease { return self; }
NSOperation的作用
配合使用NSOperation和NSOperationQueue也能实现多线程编程
NSOperation和NSOperationQueue实现多线程的具体步骤
先将需要执行的操作封装到一个NSOperation对象中
然后将NSOperation对象添加到NSOperationQueue中
系统会自动将NSOperation中封装的操作放到一条新线程中执行
NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
使用NSOperation子类的方式有3种
NSInvocationOperation
NSBlockOperation
自定义子类继承NSOperation,实现内部相应的方法
创建NSInvocationOperation对象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
调用start方法开始执行操作
- (void)start;
一旦执行操作,就会调用target的sel方法
注意
默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
创建NSBlockOperation对象
+ (id)blockOperationWithBlock:(void (^)(void))block;
通过addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
NSOperationQueue的作用
NSOperation可以调用start方法来执行任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
最大并发数的相关方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
队列的取消、暂停、恢复
- (void)cancelAllOperations;
提示:也可以调用NSOperation的- (void)cancel方法取消单个操作
- (void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- (BOOL)isSuspended;
设置NSOperation在queue中的优先级,可以改变操作的执行顺序
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
NSOperation之间可以设置依赖来保证执行顺序
比如一定要让操作A执行完后,才能执行操作B,可以这么写
[operationB addDependency:operationA]; // 操作B依赖于操作A
可以在不同queue的NSOperation之间创建依赖关系,但不能相互依赖
自定义NSOperation
重写- (void)main方法,在里面实现想执行的任务
HTTP请求:请求行、请求头、请求体
HTTP响应:响应行、响应头、响应体
在iOS中发送请求时不需要程序员写请求行和请求头,有需要时只需要写请求体
HTTP请求方式主要有两种:GET请求和POST请求
还有一种HEAD请求,Head请求可用于在文件下载时查询欲下载的大小
发送请求时的主要过程:urlStr –> NSURL –> NSMutableURLRequest –> NSURLConnection
POST过程和GET一致,只是需要设置NSMutableURLRequest的HTTPBody以及HTTPMethod,另外url与GET方式不一致.
GET方式
NSString *urlStr = [NSString stringWithFormat:@"http://192.168.1.200:8080/MJServer/login?username=%@&pwd=%@", username, pwd];
urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; // 默认就是GET请求
request.timeoutInterval = 5; // 设置请求超时
NSOperationQueue *queue = [NSOperationQueue mainQueue];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // 当请求结束的时候调用
// connectionError与data只有一个有值
}];
POST方式
NSURL *url = [NSURL URLWithString:@"http://192.168.1.200:8080/MJServer/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.timeoutInterval = 5; // 设置请求超时
request.HTTPMethod = @"POST"; // 设置为POST请求
// 通过请求头告诉服务器客户端的类型
[request setValue:@"ios" forHTTPHeaderField:@"User-Agent"];
// 设置请求体
NSString *param = [NSString stringWithFormat:@"username=%@&pwd=%@", username, pwd];
request.HTTPBody = [param dataUsingEncoding:NSUTF8StringEncoding];
NSOperationQueue *queue = [NSOperationQueue mainQueue];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { // 当请求结束的时候调用
}];
HEAD方式查询欲下载文件大小
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"HEAD";
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
totalLength = response.expectedContentLength;
ASI、AFN框架的使用见第46、47点
配置以及其他信息点击这里
请求分为同步请求和异步请求,区别在于会不会阻塞主线程
+ (void)sendAsynchronousRequest:(NSURLRequest*) request
queue:(NSOperationQueue*) queue
completionHandler:(void (^)(NSURLResponse* response, NSData* data, NSError* connectionError)) handler NS_AVAILABLE(10_7, 5_0);
data与connectionError只会一个有值.
+ (NSURLConnection*)connectionWithRequest:(NSURLRequest *)request delegate:(id)delegate;
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate;
- (instancetype)initWithRequest:(NSURLRequest *)request delegate:(id)delegate startImmediately:(BOOL)startImmediately NS_AVAILABLE(10_5, 2_0);
如果此函数最后一个参数传入NO,则不会马上开始请求。需要开始时要调用start
函数.
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
请求错误(失败)的时候调用(请求超时\断网\没有网, 一般指客户端错误)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
当接受到服务器的响应(连通了服务器)就会调用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data;
当接受到服务器的数据就会调用(可能会被调用多次, 每次调用只会传递部分数据)
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
当服务器的数据接受完毕后就会调用
e.g. 代理方法的运用
#pragma mark - NSURLConnectionDataDelegate 代理方法
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
[MBProgressHUD showError:@"网络繁忙, 请稍后再试"];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// 初始化数据
self.responseData = [NSMutableData data];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 拼接(收集)数据
[self.responseData appendData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 解析服务器返回的数据
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:self.responseData options:NSJSONReadingMutableLeaves error:nil];
NSString *error = dict[@"error"];
if (error) { // 登录失败
[MBProgressHUD showError:error];
} else { // 登录成功
NSString *success = dict[@"success"];
[MBProgressHUD showSuccess:success];
}
}
// 1.创建请求
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/video"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 2.设置缓存策略(有缓存就用缓存,没有缓存就重新请求)
request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
// 获得全局的缓存对象
NSURLCache *cache = [NSURLCache sharedURLCache];
// 定期处理缓存
// if (缓存没有达到7天) {
// request.cachePolicy = NSURLRequestReturnCacheDataElseLoad;
// }
// if (缓存达到7天) {
// [cache removeCachedResponseForRequest:request];
// }
NSCachedURLResponse *response = [cache cachedResponseForRequest:request];
if (response) {
NSLog(@"---这个请求已经存在缓存");
} else {
NSLog(@"---这个请求没有缓存");
}
JSON | OC |
---|---|
{} | NSDictionary |
[] | NSArray |
“” | NSString |
数字 | NSNumber |
在iOS中,JSON的常见解析方案有4种
第三方框架:JSONKit、SBJson、TouchJSON(性能从左到右,越差)
苹果原生(自带):NSJSONSerialization(性能最好)
NSJSONSerialization的常见方法
+ (id)JSONObjectWithData:(NSData *)data options:(NSJSONReadingOptions)opt error:(NSError **)error;
JSON数据 –> OC对象
+ (NSData *)dataWithJSONObject:(id)obj options:(NSJSONWritingOptions)opt error:(NSError **)error;
OC对象 –> JSON数据
XML的解析有2种
DOM:一次性将整个XML文档加载进内存,比较适合解析小文件
SAX:从根元素开始,按顺序一个元素一个元素往下解析,比较适合解析大文件
在iOS中,解析XML的手段有很多
苹果原生
NSXMLParser:SAX方式解析,使用简单
第三方框架
libxml2:纯C语言,默认包含在iOS SDK中,同时支持DOM和SAX方式解析
GDataXML:DOM方式解析,由Google开发,基于libxml2
XML解析方式的选择建议
大文件:NSXMLParser、libxml2
小文件:GDataXML
使用步骤
// 传入XML数据,创建解析器
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data];
// 设置代理,监听解析过程
parser.delegate = self;
// 开始解析
[parser parse];
NSXMLParser采取的是SAX方式解析,特点是事件驱动,下面情况都会通知代理
当扫描到文档(Document)的开始与结束
当扫描到元素(Element)的开始与结束
NSXMLParserDelegate
当扫描到文档的开始时调用(开始解析)
- (void)parserDidStartDocument:(NSXMLParser *)parser
当扫描到文档的结束时调用(解析完毕)
- (void)parserDidEndDocument:(NSXMLParser *)parser
当扫描到元素的开始时调用(attributeDict存放着元素的属性)
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
当扫描到元素的结束时调用
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
e.g.
#pragma mark - NSXMLParserDelegate
/** * 开始解析文档时调用 */
- (void)parserDidStartDocument:(NSXMLParser *)parser
{
}
/** * 结束解析文档时调用(解析完毕) */
- (void)parserDidEndDocument:(NSXMLParser *)parser
{
}
/** * 解析到一个元素的开头时调用 <videos> */
- (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName attributes:(NSDictionary *)attributeDict
{
if ([@"videos" isEqualToString:elementName]) { // 解析到一个videos标签
self.videos = [NSMutableArray array];
} else if ([@"video" isEqualToString:elementName]) { // 解析到一个video标签, 创建一个模型
HMVideo *video = [HMVideo videoWithDict:attributeDict];
[self.videos addObject:video];
}
}
/** * 解析到一个元素的结尾时调用 </videos> */
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName
{
}
GDataXML配置以及使用
通过设置请求头Range可以指定每次从网路下载数据包的大小
Range示例
bytes=0-499 从0到499的头500个字节
bytes=500-999 从500到999的第二个500字节
bytes=500- 从500字节以后的所有字节
bytes=-500 最后500个字节
bytes=500-599,800-899 同时指定几个范围
Range小结
-用于分隔
前面的数字表示起始字节数
后面的数组表示截止字节数,没有表示到末尾
,用于分组,可以一次指定多个Range,不过很少用
也可以使用ASI、AFN达成目的,此处仅使用原生的达成目的。
文件上传一定要用POST方式。
首先要设置请求体,请求体里面有文件参数和普通参数(格外注意请求体的格式)
然后设置请求头,并声明这个请求时个文件上传
最后发送请求
e.g.
// 文件上传
NSURL *url = [NSURL URLWithString:@"http://localhost:8080/MJServer/upload"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
// 设置请求体
NSMutableData *body = [NSMutableData data];
/***************文件参数***************/
// 参数开始的标志
[body appendData:HMEncode(@"--heima\r\n")]; //HMEncode 为UTF8编码的宏
// name : 指定参数名(必须跟服务器端保持一致)
// filename : 文件名
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename];
[body appendData:HMEncode(disposition)];
NSString *type = [NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType];
[body appendData:HMEncode(type)];
[body appendData:HMEncode(@"\r\n")];
[body appendData:data];
[body appendData:HMEncode(@"\r\n")];
/***************普通参数***************/
[params enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
// 参数开始的标志
[body appendData:HMEncode(@"--heima\r\n")];
NSString *disposition = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", key];
[body appendData:HMEncode(disposition)];
[body appendData:HMEncode(@"\r\n")];
[body appendData:HMEncode(obj)];
[body appendData:HMEncode(@"\r\n")];
}];
/***************参数结束***************/
// heima--\r\n
[body appendData:HMEncode(@"--heima--\r\n")];
request.HTTPBody = body;
// 设置请求头
// 请求体的长度
[request setValue:[NSString stringWithFormat:@"%zd", body.length] forHTTPHeaderField:@"Content-Length"];
// 声明这个POST请求是个文件上传
[request setValue:@"multipart/form-data; boundary=heima" forHTTPHeaderField:@"Content-Type"];
// 发送请求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (data) {
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
NSLog(@"%@", dict);
} else {
NSLog(@"上传失败");
}
}];
ASI配置
// 2.获得系统默认的缓存管理对象(决定着缓存存储路径)
ASIDownloadCache *cache = [ASIDownloadCache sharedCache];
// 默认的缓存加载策略 : 不读取缓存
cache.defaultCachePolicy = ASIDoNotReadFromCacheCachePolicy;
// 3.使用缓存
request.downloadCache = cache;
// 缓存加载策略
request.cachePolicy = ASIOnlyLoadIfNotCachedCachePolicy;
// 缓存存储策略(存储的时长)
request.cacheStoragePolicy = ASICachePermanentlyCacheStoragePolicy;
// 缓存加载的优先级: request.cachePolicy > cache.defaultCachePolicy
// 2.获得系统默认的缓存管理对象(决定着缓存存储路径)
ASIDownloadCache *cache = [ASIDownloadCache sharedCache]; // 默认的缓存加载策略 : 不读取缓存 cache.defaultCachePolicy = ASIDoNotReadFromCacheCachePolicy; [ASIHTTPRequest setDefaultCache:cache];
[request startAsynchronous]
发送异步请求
[request startSynchronous]
发送同步请求
GET请求
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL: url];
POST请求
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url1];
// 添加普通参数(非文件参数,文件参数见下)
[request setPostValue:@”dasda” forKey:@”username”];
[request setPostValue:@”1515” forKey:@”pwd”];
// 1.创建请求对象
NSURL *url = [NSURL URLWithString:@"http://192.168.1.200:8080/MJServer/resources/jre.zip"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
// 2.设置所下载文件的存储路径
NSString *cache = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *filepath = [cache stringByAppendingPathComponent:@"jre.zip"];
request.downloadDestinationPath = filepath;
// 3.设置下载代理(可以直接设置一个有setProgress函数的对象,若没有,则需要实现setProgress方法)
request.downloadProgressDelegate = self.circleView;
// 4.支持断点下载
request.allowResumeForFileDownloads = YES;
// 5.发送请求
[request startAsynchronous];
// 1.创建请求
NSURL *url = [NSURL URLWithString:@"http://192.168.1.200:8080/MJServer/upload"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
// 2.设置(指定)所要上传文件的路径
NSString *caches = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
NSString *file = [caches stringByAppendingPathComponent:@"jre.zip"];
[request setFile:file forKey:@"file"];
// [request setFile:file withFileName:@"123.txt" andContentType:@"text/plain" forKey:@"file"];
// 3.设置其他请求参数
[request setPostValue:@"zhangsan" forKey:@"username"];
// 设置代理监听上传进度
request.uploadProgressDelegate = self.circleView;
// 4.发送请求
[request startAsynchronous];
// 程序进入后台, 继续发送请求
request.shouldContinueWhenAppEntersBackground = YES;
// 5.监听请求
[request setCompletionBlock:^{
NSLog(@"上传完毕");
}];
[request setStartedBlock:^{ }];
[request setDataReceivedBlock:^(NSData *data) { }];
[request setCompletionBlock:^{ }];
[request setFailedBlock:^{ }];
获得响应头信息
@property (atomic, retain) NSDictionary *responseHeaders;
获得响应体(实体内容)
- (NSData *)responseData
- (NSString *)responseString
ASI的网络监测使用的是Reachability
在AFN中,GET请求和POSY请求只是方法名不同而已(一为GET,另一为POST)
GET
// 1.获得请求管理者(管理请求, 帮助发请求)
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 声明服务器返回的数据是JSON
// mgr.responseSerializer = [AFJSONResponseSerializer serializer];
// 2.封装请求参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
// 3.发送GET请求
[mgr GET:@"http://192.168.1.200:8080/MJServer/login" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
// responseObject : 在这种情况下是字典
NSLog(@"请求成功---%@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"请求失败---%@", error);
}];
POST
// 1.获得请求管理者(管理请求, 帮助发请求)
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 声明服务器返回的数据是JSON
// mgr.responseSerializer = [AFJSONResponseSerializer serializer];
// 2.封装请求参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"123";
params[@"pwd"] = @"123";
// 3.发送GET请求
[mgr POST:@"http://192.168.1.200:8080/MJServer/login" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
// responseObject : 在这种情况下是字典
NSLog(@"请求成功---%@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"请求失败---%@", error);
}];
// 1.获得请求管理者
AFHTTPRequestOperationManager *mgr = [AFHTTPRequestOperationManager manager];
// 2.发送请求(做文件上传)
// parameters : 只能放非文件参数
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"username"] = @"zhangsan";
[mgr POST:@"http://192.168.1.200:8080/MJServer/upload" parameters:params
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// 一定要在这个block中添加文件参数
// 加载文件数据
NSString *file = [[NSBundle mainBundle] pathForResource:@"test.txt" ofType:nil];
NSData *data = [NSData dataWithContentsOfFile:file];
// 拼接文件参数
[formData appendPartWithFileData:data name:@"file" fileName:@"123.txt" mimeType:@"text/plain"];
} success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"上传成功----%@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"上传失败----%@", error);
}];
// 1.获得网络监控的管理者
AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager];
// 2.设置网络状态改变后的处理
[mgr setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) {
// 当网络状态改变了, 就会调用这个block
switch (status) {
case AFNetworkReachabilityStatusUnknown: // 未知网络
NSLog(@"未知网络");
break;
case AFNetworkReachabilityStatusNotReachable: // 没有网络(断网)
NSLog(@"没有网络(断网)");
break;
case AFNetworkReachabilityStatusReachableViaWWAN: // 手机自带网络
NSLog(@"手机自带网络");
break;
case AFNetworkReachabilityStatusReachableViaWiFi: // WIFI
NSLog(@"WIFI");
break;
}
}];
// 3.开始监控
[mgr startMonitoring];
// mgr.isReachableViaWiFi
// mgr.isReachableViaWWAN
UIWebView在跳转网页前都会调用代理的
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;
函数。以此函数为桥梁可以实现网页调用OC代码
e.g.
/** 当webView发送一个请求之前都会调用这个方法, 返回YES, 可以加载这个请求, 返回NO, 代表禁止加载这个请求 */
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *url = request.URL.absoluteString;
NSRange range = [url rangeOfString:@"ios://"];
if (range.length != 0) {
// 截取方法名
NSString *method = [url substringFromIndex:range.location + range.length];
// 将方法名转为SEL类型
SEL selector = NSSelectorFromString(method);
[self performSelector:selector withObject:nil];
}
return YES;
}