一. block实现反向传值
二. block封装下载类型
三. GCD基本概念
GCD是iOS4之后的技术, 是基于C语言来实现的, 速度更快, 效率更高
通常使用GCD来实现多线程
四. GCD的使用
五. GCD下载图片
六. GCD扩展
七. 抓包(选项目)
这里使用paros.jar来抓包
下载安装JAVA SDK环境: Oracle官网: Downloads - JAVA SE - SDK - MACOS 64bit
如果还是无法打开paros.jar, 请将paros相关文件放至在英文目录下
获取电脑在当前局域网内的IP: 192.168.80.15
保证手机和电脑在同一个网段下
a) 连上同一个wifi
b) 在电脑上设一个热点, 手机连接该热点
手机进入Wi-Fi界面, 进入连接的网络, 滑到最下方, 设置HTTP代理, 改为手动模式, 服务器设为电脑的IP, 设置一个较大的端口, 如8080或8888(charles抓包软件默认端口)
此时打开paros.jar即可检测到设备的网络活动
a)打开iTunes,进入apple store界面
b)选中一个应用,点击进入应用的详情介绍界面
c)点击“获取”按钮,下载这个应用
d)下载完成之后,找到下载的这个应用,右击选择“show In Finder”,显示ipa文件
e)右击ipa文件->打开方式->归档工具
f)在生成的文件夹下面,有一个payload文件夹,选中文件夹下面的文件,右击->显示包内容,这样就能够看到应用所用的资源文件
1)html文件,three20第三方库,直接用UIWebView显示这个链接
2)有些应用Andriod和iphone的接口不一样
一. block实现反向传值
1. 实现常规的导航控制器push跳转页面功能
//
// ViewController.m
// 01_BlockReverseValues
#import "ViewController.h"
#import "MyUtility.h"
#import "DetailViewController.h"
@interface ViewController ()
@property (nonatomic, strong) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
// 显示文字
_label = [[UILabel alloc] initWithFrame:CGRectMake(50, 100, 100, 40)];
[self.view addSubview:_label];
// 创建按钮
UIButton *btn = [MyUtility createButtonWithFrame:CGRectMake(100, 200, 80, 40) title:@"跳转" backgroundImageName:nil target:self action:@selector(gotoNextPage)];
[self.view addSubview:btn];
}
- (void)gotoNextPage
{
DetailViewController *dvc = [[DetailViewController alloc] init];
[self.navigationController pushViewController:dvc animated:YES];
};
}
//
// DetailViewController.h
// 01_BlockReverseValues
#import <UIKit/UIKit.h>
@interface DetailViewController : UIViewController
@end
#import "DetailViewController.h"
#import "MyUtility.h"
@implementation DetailViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
[self createBtns];
}
- (void)createBtns
{
UIButton *btn1 = [MyUtility createButtonWithFrame:CGRectMake(100, 100, 80, 40) title:@"Button1" backgroundImageName:nil target:self action:@selector(clickBtn:)];
UIButton *btn2 = [MyUtility createButtonWithFrame:CGRectMake(100, 200, 80, 40) title:@"Button2" backgroundImageName:nil target:self action:@selector(clickBtn:)];
UIButton *btn3 = [MyUtility createButtonWithFrame:CGRectMake(100, 300, 80, 40) title:@"Button3" backgroundImageName:nil target:self action:@selector(clickBtn:)];
[self.view addSubview:btn1];
[self.view addSubview:btn2];
[self.view addSubview:btn3];
}
@end
2. 增加利用block传值的代码
-
ViewController的gotoNextPage方法
- (void)gotoNextPage
{
DetailViewController *dvc = [[DetailViewController alloc] init];
[self.navigationController pushViewController:dvc animated:YES];// 给block赋值 __weak ViewController *weakSelf = self; dvc.clickBlock = ^(NSString *title){ // 修改Label上面的文字 weakSelf.label.text = title; }; }
-
为DetailViewController类增加一个block属性, 在点击按钮执行的方法中由该block属性来处理需要反向传递的值
@interface DetailViewController : UIViewController // block传值 @property (nonatomic, copy) void (^clickBlock)(NSString *param); @end @implementation DetailViewController - (void)clickBtn:(UIButton *)sender { NSString *title = sender.currentTitle; // [sender titleForState:UIControlStateNormal]; // 使用 if (self.clickBlock) { self.clickBlock(title); } }
二. block封装下载类型
1. 按照常规步骤编写MyDownloader类, 下载结束和下载失败的代码暂不处理
//
// MyDownloader.h
// 02_BlockDownloader
#import <Foundation/Foundation.h>
@interface MyDownloader : NSObject <NSURLConnectionDataDelegate, NSURLConnectionDelegate>
// 下载数据
- (void)downloadWithURLString:(NSString *)urlString
@end
//
// MyDownloader.m
// 02_BlockDownloader
#import "MyDownloader.h"
@implementation MyDownloader
{
// 下载数据
NSMutableData *_receiveData;
// 下载对象
NSURLConnection *_connection;
}
- (instancetype)init
{
self = [super init];
if (self) {
// 初始化下载数据
_receiveData = [NSMutableData data];
}
return self;
}
- (void)downloadWithURLString:(NSString *)urlString
{
_connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] delegate:self];
}
#pragma mark - NSURLConnection
// 下载失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
}
// 每次数据下载回来后
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receiveData appendData:data];
}
// 请求响应
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[_receiveData setLength:0];
}
// 下载成功
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
}
@end
2. 修改MyDownload类: 修改下载数据的公开方法, 令其包含参数类型为NSData(下载结束所得的数据类型)的block参数和 参数类型为NSError(下载失败所得的数据类型的)block参数, 并各自增加该类型的block作为成员变量
// 把变量名去掉就是block的类型
// 下载数据
- (void)downloadWithURLString:(NSString *)urlString finishBlock:(void (^)(NSData *data))finishBlock failBlock:(void (^)(NSError *error))failBlock;
//
// MyDownloader.m
// 02_BlockDownloader
#import "MyDownloader.h"
@implementation MyDownloader
{
…………………………………………………………………………………………
// 声明
// 下载成功
void (^_finishBlock)(NSData *data);
// 下载失败
void (^_failBlock)(NSError *error);
}
…………………………………………………………………………………………
- (void)downloadWithURLString:(NSString *)urlString finishBlock:(void (^)(NSData *))finishBlock failBlock:(void (^)(NSError *))failBlock
{
// block的赋值
// 给block成员变量赋值
if (_finishBlock != finishBlock) {
_finishBlock = nil;
_finishBlock = finishBlock;
}
if (_failBlock != failBlock) {
_failBlock = nil;
_failBlock = failBlock;
}
_connection = [NSURLConnection connectionWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] delegate:self];
}
#pragma mark - NSURLConnection
// 下载失败
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// 调用
if (_failBlock) {
_failBlock(error);
}
}
// 每次数据下载回来后
…………………………………………………………………………………………
// 请求响应
…………………………………………………………………………………………
// 下载成功
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 调用
if (_finishBlock) {
_finishBlock(_receiveData);
}
}
@end
3. 在ViewController.m中导入MyDownloader类使用
#import "ViewController.h"
#import "MyDownloader.h"
// 下载链接
#define kLimitUrl (@"http://iappfree.candou.com:8080/free/applications/limited?currency=rmb&page=1")
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
MyDownloader *downloader = [[MyDownloader alloc] init];
[downloader downloadWithURLString:kLimitUrl finishBlock:^(NSData *data) {
// 解析数据
id result = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
if ([result isKindOfClass:[NSDictionary class]]) {
NSDictionary *dict = result;
NSArray *array = dict[@"applications"];
NSLog(@"%@", array);
}
} failBlock:^(NSError *error) {
NSLog(@"%@", error);
}];
}
三. GCD基本概念
- GCD的队列
- 主线程所在的串行队列
串行队列的意思是前面的代码执行完成, 才开始执行后面的代码
并行队列是前面的代码和后面的代码同时开始执行, 并行运行的方式效率更高
dispatch_queue_t mainQueue = dispatch_get_main_queue(); - 全局的并行队列
- 自己创建的队列:
- 并行队列
- 串行队列
- 怎样实现线程
同步的提交(不能让主线程(串行)同步执行一段代码, 程序会卡死)
-
异步的提交
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.// GCD实现多线程是将代码块(线程的执行体)提交到队列里面执行
// 1. GCD的队列
// 1) 主线程所在的串行队列
// 串行队列的意思是前面的代码执行完成, 才开始执行后面的代码
// 并行队列是前面的代码和后面的代码同时开始执行, 并行运行的方式效率更高
dispatch_queue_t mainQueue = dispatch_get_main_queue();// 2) 全局的并行队列
/*
第一个参数: 队列的优先级
第二个参数: 是apple预留的一个参数, 传0即可
*/
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 3) 自己创建的队列
/*
第一个参数: 队列的标识符
第二个参数: 用来区分串行还是并行
DISPATCH_QUEUE_SERIAL 串行
DISPATCH_QUEUE_CONCURRENT 并行
*/
// a) 串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("serialQueue", DISPATCH_QUEUE_SERIAL);
// b) 并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrentQueue", DISPATCH_QUEUE_CONCURRENT);// 2. 怎样实现线程
// 1) 同步的提交(不能让主线程(串行)同步执行一段代码, 程序会卡住直到代码运行完成)
/*
第一个参数: 线程在哪个队列执行
第二个参数: 代码块, 线程的执行体
*/
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了任务1: %d", i);
}
});// 2) 异步的提交
/*
第一个参数: 线程在哪个队列执行
第二个参数: 代码块, 线程的执行体
*/
dispatch_async(mainQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了任务2: %d", i);
}
});
}
-
四. GCD的使用
1. 以同步的方式向串行队列提交代码
/*
前面的线程执行完毕之后, 才开始执行后面的线程
*/
- (void)testSyncMethodWithSerialQueue
{
// 创建一个串行的队列
dispatch_queue_t serialQueue = dispatch_queue_create("Queue1", DISPATCH_QUEUE_SERIAL);
// 以同步的方式提交两个代码块
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务1: %d", [NSThread currentThread], i);
}
});
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务2: %d", [NSThread currentThread], i);
}
});
}
2. 以同步的方式向并行队列提交代码
/*
前面的线程执行完毕之后, 才开始执行后面的线程
*/
- (void)testSyncMethodWithConcurrentQueue
{
// 获取全局队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 以同步的方式创建两个代码块
dispatch_sync(globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务1: %d", [NSThread currentThread], i);
}
});
dispatch_sync(globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务2: %d", [NSThread currentThread], i);
}
});
}
3. 以异步的方式向串行队列提交代码
- (void)testAsyncMethodWithserialQueue
{
// 创建串行队列
dispatch_queue_t serialQueue = dispatch_queue_create("queueThree", DISPATCH_QUEUE_SERIAL);
// 异步提交两个代码块
dispatch_async(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务1: %d", [NSThread currentThread], i);
}
});
dispatch_async(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务2: %d", [NSThread currentThread], i);
}
});
}
4. 以异步的方式向并行队列提交代码
- (void)testAsyncMethodWithConcurrentQueue
{
// 创建并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("queueFour", DISPATCH_QUEUE_CONCURRENT);
// 异步提交两段代码块
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务1: %d", [NSThread currentThread], i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@执行了任务2: %d", [NSThread currentThread], i);
}
});
}
五. GCD下载图片
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 使用GCD下载图片
// @"http://img3.3lian.com/2006/027/08/007.jpg"
// 获取全局并行队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 向队列中异步提交代码块
__weak ViewController *weakSelf = self;
dispatch_async(globalQueue, ^{
// 下载图片
NSURL *url = [NSURL URLWithString:@"http://img3.3lian.com/2006/027/08/007.jpg"];
// 下载数据
NSData *data = [NSData dataWithContentsOfURL:url];
// 下载完成后回到主线程修改UI
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(40, 100, 240, 320)];
imageView.image = [UIImage imageWithData:data];
[weakSelf.view addSubview:imageView];
});
});
}
六. GCD扩展
1. 代码执行多次
- (void)testMultiTimes
{
/*
第一个参数: 执行的次数
第二个参数: 代码执行体所在的队列
第三个参数: 线程的执行体(代码块)
*/
dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t time) {
// time 表示现在执行的是第几次
NSLog(@"执行第%zu次", time);
});
/*
执行结果是无序的
2015-06-12 14:28:25.975 06_GCDMore[1195:23542] 执行第0次
2015-06-12 14:28:25.975 06_GCDMore[1195:23643] 执行第1次
2015-06-12 14:28:25.975 06_GCDMore[1195:23644] 执行第2次
2015-06-12 14:28:25.976 06_GCDMore[1195:23542] 执行第4次
2015-06-12 14:28:25.975 06_GCDMore[1195:23645] 执行第3次
*/
}
2. 代码在一段时间之后运行
- (void)testGCDAfter
{
NSLog(@"now");
// 时间值
// 十秒之后
dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10);
/*
第一个参数: 线程执行的时间
第二个参数: 线程执行的队列
第三个参数: 线程的执行体
*/
dispatch_after(t, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"after");
});
}
3. 代码在程序运行期间只执行一次
// 通常用来实现单例
- (void)testGDCOnlyOnce
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"代码执行1次");
});
}
4. Group: 在几个线程都执行完成之后需要(才)做一些操作
- (void)testGDCGroup
{
// 创建一个Group
dispatch_group_t myGroup = dispatch_group_create();
// 队列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 执行两个线程
/*
第一个参数: group
第二个参数: 队列
第三个参数: 线程的执行体
*/
dispatch_group_async(myGroup, globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程1:%d", i);
}
});
dispatch_group_async(myGroup, globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程2:%d", i);
}
});
// 在两个线程都执行完成之后, 执行一些操作
dispatch_group_notify(myGroup, globalQueue, ^{
NSLog(@"两个线程都执行完成");
NSLog(@"%s", __func__);
});
}
5. 让所有的线程分成2部分
- (void)testGCDBarrier
{
// 并行队列
// 这种方式只能使用自己创建的并行队列
dispatch_queue_t concurrentQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程1:%d" ,i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程2:%d" ,i);
}
});
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"Barrier");
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程3:%d" ,i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"执行了线程4:%d" ,i);
}
});
}