一. block實現(xiàn)反向傳值
二. block封裝下載類型
三. GCD基本概念
GCD是iOS4之后的技術(shù), 是基于C語言來實現(xiàn)的, 速度更快, 效率更高
通常使用GCD來實現(xiàn)多線程
四. GCD的使用
五. GCD下載圖片
六. GCD擴展
七. 抓包(選項目)
這里使用paros.jar來抓包
下載安裝JAVA SDK環(huán)境: Oracle官網(wǎng): Downloads - JAVA SE - SDK - MACOS 64bit
如果還是無法打開paros.jar, 請將paros相關(guān)文件放至在英文目錄下
獲取電腦在當(dāng)前局域網(wǎng)內(nèi)的IP: 192.168.80.15
保證手機和電腦在同一個網(wǎng)段下
a) 連上同一個wifi
b) 在電腦上設(shè)一個熱點, 手機連接該熱點
手機進(jìn)入Wi-Fi界面, 進(jìn)入連接的網(wǎng)絡(luò), 滑到最下方, 設(shè)置HTTP代理, 改為手動模式, 服務(wù)器設(shè)為電腦的IP, 設(shè)置一個較大的端口, 如8080或8888(charles抓包軟件默認(rèn)端口)
此時打開paros.jar即可檢測到設(shè)備的網(wǎng)絡(luò)活動
a)打開iTunes捺信,進(jìn)入apple store界面
b)選中一個應(yīng)用酌媒,點擊進(jìn)入應(yīng)用的詳情介紹界面
c)點擊“獲取”按鈕,下載這個應(yīng)用
d)下載完成之后迄靠,找到下載的這個應(yīng)用秒咨,右擊選擇“show In Finder”,顯示ipa文件
e)右擊ipa文件->打開方式->歸檔工具
f)在生成的文件夾下面,有一個payload文件夾掌挚,選中文件夾下面的文件,右擊->顯示包內(nèi)容,這樣就能夠看到應(yīng)用所用的資源文件
1)html文件,three20第三方庫,直接用UIWebView顯示這個鏈接
2)有些應(yīng)用Andriod和iphone的接口不一樣
一. block實現(xiàn)反向傳值
1. 實現(xiàn)常規(guī)的導(dǎo)航控制器push跳轉(zhuǎn)頁面功能
//
// 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];
// 創(chuàng)建按鈕
UIButton *btn = [MyUtility createButtonWithFrame:CGRectMake(100, 200, 80, 40) title:@"跳轉(zhuǎn)" 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屬性, 在點擊按鈕執(zhí)行的方法中由該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. 按照常規(guī)步驟編寫MyDownloader類, 下載結(jié)束和下載失敗的代碼暫不處理
//
// MyDownloader.h
// 02_BlockDownloader
#import <Foundation/Foundation.h>
@interface MyDownloader : NSObject <NSURLConnectionDataDelegate, NSURLConnectionDelegate>
// 下載數(shù)據(jù)
- (void)downloadWithURLString:(NSString *)urlString
@end
//
// MyDownloader.m
// 02_BlockDownloader
#import "MyDownloader.h"
@implementation MyDownloader
{
// 下載數(shù)據(jù)
NSMutableData *_receiveData;
// 下載對象
NSURLConnection *_connection;
}
- (instancetype)init
{
self = [super init];
if (self) {
// 初始化下載數(shù)據(jù)
_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
{
}
// 每次數(shù)據(jù)下載回來后
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[_receiveData appendData:data];
}
// 請求響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[_receiveData setLength:0];
}
// 下載成功
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
}
@end
2. 修改MyDownload類: 修改下載數(shù)據(jù)的公開方法, 令其包含參數(shù)類型為NSData(下載結(jié)束所得的數(shù)據(jù)類型)的block參數(shù)和 參數(shù)類型為NSError(下載失敗所得的數(shù)據(jù)類型的)block參數(shù), 并各自增加該類型的block作為成員變量
// 把變量名去掉就是block的類型
// 下載數(shù)據(jù)
- (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
{
// 調(diào)用
if (_failBlock) {
_failBlock(error);
}
}
// 每次數(shù)據(jù)下載回來后
…………………………………………………………………………………………
// 請求響應(yīng)
…………………………………………………………………………………………
// 下載成功
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 調(diào)用
if (_finishBlock) {
_finishBlock(_receiveData);
}
}
@end
3. 在ViewController.m中導(dǎo)入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) {
// 解析數(shù)據(jù)
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的隊列
- 主線程所在的串行隊列
串行隊列的意思是前面的代碼執(zhí)行完成, 才開始執(zhí)行后面的代碼
并行隊列是前面的代碼和后面的代碼同時開始執(zhí)行, 并行運行的方式效率更高
dispatch_queue_t mainQueue = dispatch_get_main_queue(); - 全局的并行隊列
- 自己創(chuàng)建的隊列:
- 并行隊列
- 串行隊列
- 怎樣實現(xiàn)線程
同步的提交(不能讓主線程(串行)同步執(zhí)行一段代碼, 程序會卡死)
-
異步的提交
-
(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.// GCD實現(xiàn)多線程是將代碼塊(線程的執(zhí)行體)提交到隊列里面執(zhí)行
// 1. GCD的隊列
// 1) 主線程所在的串行隊列
// 串行隊列的意思是前面的代碼執(zhí)行完成, 才開始執(zhí)行后面的代碼
// 并行隊列是前面的代碼和后面的代碼同時開始執(zhí)行, 并行運行的方式效率更高
dispatch_queue_t mainQueue = dispatch_get_main_queue();// 2) 全局的并行隊列
/*
第一個參數(shù): 隊列的優(yōu)先級
第二個參數(shù): 是apple預(yù)留的一個參數(shù), 傳0即可
*/
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);// 3) 自己創(chuàng)建的隊列
/*
第一個參數(shù): 隊列的標(biāo)識符
第二個參數(shù): 用來區(qū)分串行還是并行
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. 怎樣實現(xiàn)線程
// 1) 同步的提交(不能讓主線程(串行)同步執(zhí)行一段代碼, 程序會卡住直到代碼運行完成)
/*
第一個參數(shù): 線程在哪個隊列執(zhí)行
第二個參數(shù): 代碼塊, 線程的執(zhí)行體
*/
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了任務(wù)1: %d", i);
}
});// 2) 異步的提交
/*
第一個參數(shù): 線程在哪個隊列執(zhí)行
第二個參數(shù): 代碼塊, 線程的執(zhí)行體
*/
dispatch_async(mainQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了任務(wù)2: %d", i);
}
});
}
-
四. GCD的使用
1. 以同步的方式向串行隊列提交代碼
/*
前面的線程執(zhí)行完畢之后, 才開始執(zhí)行后面的線程
*/
- (void)testSyncMethodWithSerialQueue
{
// 創(chuàng)建一個串行的隊列
dispatch_queue_t serialQueue = dispatch_queue_create("Queue1", DISPATCH_QUEUE_SERIAL);
// 以同步的方式提交兩個代碼塊
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)1: %d", [NSThread currentThread], i);
}
});
dispatch_sync(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)2: %d", [NSThread currentThread], i);
}
});
}
2. 以同步的方式向并行隊列提交代碼
/*
前面的線程執(zhí)行完畢之后, 才開始執(zhí)行后面的線程
*/
- (void)testSyncMethodWithConcurrentQueue
{
// 獲取全局隊列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 以同步的方式創(chuàng)建兩個代碼塊
dispatch_sync(globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)1: %d", [NSThread currentThread], i);
}
});
dispatch_sync(globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)2: %d", [NSThread currentThread], i);
}
});
}
3. 以異步的方式向串行隊列提交代碼
- (void)testAsyncMethodWithserialQueue
{
// 創(chuàng)建串行隊列
dispatch_queue_t serialQueue = dispatch_queue_create("queueThree", DISPATCH_QUEUE_SERIAL);
// 異步提交兩個代碼塊
dispatch_async(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)1: %d", [NSThread currentThread], i);
}
});
dispatch_async(serialQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)2: %d", [NSThread currentThread], i);
}
});
}
4. 以異步的方式向并行隊列提交代碼
- (void)testAsyncMethodWithConcurrentQueue
{
// 創(chuàng)建并行隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("queueFour", DISPATCH_QUEUE_CONCURRENT);
// 異步提交兩段代碼塊
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)1: %d", [NSThread currentThread], i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"%@執(zhí)行了任務(wù)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"];
// 下載數(shù)據(jù)
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. 代碼執(zhí)行多次
- (void)testMultiTimes
{
/*
第一個參數(shù): 執(zhí)行的次數(shù)
第二個參數(shù): 代碼執(zhí)行體所在的隊列
第三個參數(shù): 線程的執(zhí)行體(代碼塊)
*/
dispatch_apply(5, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t time) {
// time 表示現(xiàn)在執(zhí)行的是第幾次
NSLog(@"執(zhí)行第%zu次", time);
});
/*
執(zhí)行結(jié)果是無序的
2015-06-12 14:28:25.975 06_GCDMore[1195:23542] 執(zhí)行第0次
2015-06-12 14:28:25.975 06_GCDMore[1195:23643] 執(zhí)行第1次
2015-06-12 14:28:25.975 06_GCDMore[1195:23644] 執(zhí)行第2次
2015-06-12 14:28:25.976 06_GCDMore[1195:23542] 執(zhí)行第4次
2015-06-12 14:28:25.975 06_GCDMore[1195:23645] 執(zhí)行第3次
*/
}
2. 代碼在一段時間之后運行
- (void)testGCDAfter
{
NSLog(@"now");
// 時間值
// 十秒之后
dispatch_time_t t = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 10);
/*
第一個參數(shù): 線程執(zhí)行的時間
第二個參數(shù): 線程執(zhí)行的隊列
第三個參數(shù): 線程的執(zhí)行體
*/
dispatch_after(t, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"after");
});
}
3. 代碼在程序運行期間只執(zhí)行一次
// 通常用來實現(xiàn)單例
- (void)testGDCOnlyOnce
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"代碼執(zhí)行1次");
});
}
4. Group: 在幾個線程都執(zhí)行完成之后需要(才)做一些操作
- (void)testGDCGroup
{
// 創(chuàng)建一個Group
dispatch_group_t myGroup = dispatch_group_create();
// 隊列
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 執(zhí)行兩個線程
/*
第一個參數(shù): group
第二個參數(shù): 隊列
第三個參數(shù): 線程的執(zhí)行體
*/
dispatch_group_async(myGroup, globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程1:%d", i);
}
});
dispatch_group_async(myGroup, globalQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程2:%d", i);
}
});
// 在兩個線程都執(zhí)行完成之后, 執(zhí)行一些操作
dispatch_group_notify(myGroup, globalQueue, ^{
NSLog(@"兩個線程都執(zhí)行完成");
NSLog(@"%s", __func__);
});
}
5. 讓所有的線程分成2部分
- (void)testGCDBarrier
{
// 并行隊列
// 這種方式只能使用自己創(chuàng)建的并行隊列
dispatch_queue_t concurrentQueue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程1:%d" ,i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程2:%d" ,i);
}
});
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"Barrier");
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程3:%d" ,i);
}
});
dispatch_async(concurrentQueue, ^{
for (int i = 0; i < 100; i++) {
NSLog(@"執(zhí)行了線程4:%d" ,i);
}
});
}