导航:首页 > 废水知识 > 用block保存异步回调的数据

用block保存异步回调的数据

发布时间:2021-01-28 07:11:04

❶ block调用时变量的生命周期有哪几种

Block内存来管理的规则:
源1,Block指针会在方法或函数结束后release掉,此时内存是储存在Stack里。
2,如果要在保存Block指针,需要用到方法(类似于NSObject),此时内存储存在Heap里。
3,Block函数体里的变量会被自动Retain,等Block结束掉后会Release。
4,__block 前缀标明的变量,不会自动Reatin。
Block Copy时的注意事项:
1,在block里如果直接操作self,则self会自动retain。
2,在block里如果操作类变量,则变量所属的类会自动retain

❷ block的嵌套调用方式,2个block怎么相互嵌套

Block 变量拥有 blocks 的引用。你可以使用和声明函数指针类似的语法来声明它 们,除了它们使用^修饰符来替代 * 修饰符。Block 类型可以完全操作其他 C 系统 类型。以下都是合法的 block 声明:
void (^)(void);
int (^)(int, char);
void (^[10])(int);

Blocks 还支持可变参数(...)。一个没有使用任何参数的 block 必须在参数列表 上面用 void 标明。
Blocks 被设计为类型安全的,它通过给编译器完整的元数据来合法使用 blocks、 传递到 blocks 的参数和分配的返回值。你可以把一个 block 引用强制转换为任意类型 的指针,反之亦然。但是你不能通过修饰符 * 来解引用一个 block,因此一个 block 的大小是无法在编译的时候计算的。
你同样可以创建 blocks 的类型。当你在多个地方使用同一个给定的签名的 block 时,这通常被认为是最佳的办法。
typedef float (^MyBlockType)(float, float);
MyBlockType myFirstBlock = // ... ;
MyBlockType mySecondBlock = // ... ;

3.2 创建一个block
你可以使用 ^ 修饰符来标识一个 block 表达式的开始。它通常后面跟着一个被 () 包含起来的参数列表。Block 的主体一般被包含在 {} 里面。下面的示例定义了一个 简单的 block,并把它赋值给前面声明的变量(oneFrom)。这里 block 使用一个标准 C 的结束符 ; 来结束。
int (^oneFrom)(int);
oneFrom = ^(int anInt) {
return anInt - 1;
};
如果你没有显式的给 block 表达式声明一个返回值,它会自动的从 block 内容推 断出来。如果返回值是推断的,而且参数列表也是 void,那么你同样可以省略参数列 表的 void。如果或者当出现多个返回状态的时候,它们必须是完全匹配的(如果有必 要可以使用强制转换)。
3.3 全局blocks

在文件级别,你可以把 block 作为全局标示符:
#import

int GlobalInt = 0;
int (^getGlobalInt)(void) = ^{ return GlobalInt; };
第四章 Blocks和变量
本文描述 blocks 和变量之间的交互,包括内存管理。
你可以引用三种标准类型的变量,就像你在函数里面引用那样:
全局变量,包括静态局部变量。
全局函数(在技术上而言这不是变量)。
封闭范围内的局部变量和参数。
Blocks 同样支持其他两种类型的变量:
在函数级别是__block变量。这些在block里面是可变的(和封闭范围),并任何引
用 block 的都被保存一份副本到堆里面。
引入const。
最后,在实现方法里面,blocks也许会引用Objective-C的实例变量。参阅“对象
和 Block 变量”部分。
在 block 里面使用变量遵循以下规则:
全局变量可访问,包括在相同作用域范围内的静态变量。
传递给block的参数可访问(和函数的参数一样)。
程序里面属于同一作用域范围的堆(非静态的)变量作为const变量(即只读)。
它们的值在程序里面的 block 表达式内使用。在嵌套 block 里面,该值在最近的
封闭范围内被捕获。
属于同一作用域范围内并被__block存储修饰符标识的变量作为引用传递因此是
可变的。
属于同一作用域范围内block的变量,就和函数的局部变量操作一样。
每次调用 block 都提供了变量的一个拷贝。这些变量可以作为 const 来使用,或在 block 封闭范围内作为引用变量。
下面的例子演示了使用本地非静态变量:
int x = 123;
void (^printXAndY)(int) = ^(int y) {
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 123 456
正如上面提到的,在 block 内试图给 x 赋一个新值会导致错误发生:
int x = 123;
void (^printXAndY)(int) = ^(int y) {
x = x + y; // error
printf("%d %d\n", x, y);
};
为了可以在 block 内修改一个变量,你需要使用__block 存储类型修饰符来标识该 变量。参阅“__block 存储类型”部分。
4.2 __block存储类型
你可以指定引入一个变量为可更改的,即读-写的,通过应用__block 存储类型修 饰符。局部变量的__block 的存储和 register、auto、static 等存储类型相似,但它们之 间不兼容。
__block 变量保存在变量共享的作用域范围内,所有的 blocks 和 block 副本都声明 或创建在和变量的作用域相同范围内。所以,如果任何 blocks 副本声明在栈内并未超 出栈的结束时,该存储会让栈帧免于被破坏(比如封装为以后执行)。同一作用域范 围内给定的多个 block 可以同时使用一个共享变量。
作为一种优化,block存储在栈上面,就像blocks本身一样。如果使用Block_ 拷贝了 block 的一个副本(或者在 Objective-C 里面给 block 发送了一条 消息), 变量会被拷贝到堆上面。所以一个__block 变量的地址可以随时间推移而被更改。
使用__block 的变量有两个限制:它们不能是可变长的数组,并且它们不能是包 含有 C99 可变长度的数组变量的数据结构。
以下举例说明了如何使用__block 变量:
__block int x = 123; // x lives in block storage
void (^printXAndY)(int) = ^(int y) {

x = x + y;
printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579

下面的例子显示了 blocks 和其他几个类型变量间的交互:
extern NSInteger CounterGlobal;
static NSInteger CounterStatic;

{
NSInteger localCounter = 42;
__block char localCharacter;
void (^aBlock)(void) = ^(void) {

++CounterGlobal;
++CounterStatic;
CounterGlobal = localCounter; // localCounter fixed at block creation
localCharacter = 'a'; // sets localCharacter in enclosing scope

};
++localCounter; // unseen by the block
localCharacter = 'b';
aBlock(); // execute the block
// localCharacter now 'a'
}

4.3 对象(Object)和Block变量
Block 提供了支持 Objective-C 和 Objective-C++的对象,和其他 blocks 的变量。
4.3.1 Objective-C对象
在引用计数的环境里面,默认情况下当你在 block 里面引用一个 Objective-C 对象的时 候,该对象会被retain。当你简单的引用了一个对象的实例变量时,它同样被 retain。 但是被__block 存储类型修饰符标记的对象变量不会被 retain. 注意:在垃圾回收机制里面,如果你同时使用__weak 和__block 来标识一个变量,那么该 block 将不会保证它是一直是有效的。
如果你在实现方法的时候使用了 block,对象的内存管理规则更微妙:
如果你通过引用来访问一个实例变量,self 会被 retain。
如果你通过值来访问一个实例变量,那么变量会被 retain。
下面举例说明两个方式的不同:
dispatch_async(queue, ^{

// instanceVariable is used by reference, self is retained
doSomethingWithObject(instanceVariable);

});

id localVariable = instanceVariable;

dispatch_async(queue, ^{

// localVariable is used by value, localVariable is retained (not self)

doSomethingWithObject(localVariable);

4.3.2 C++对象
通常你可以在 block 内使用 C++的对象。在成员函数里面,通过隐式的导入 this 指针引用成员变量和函数,结果会很微妙。有两个条件可以让 block 被拷贝:
如果你拥有__block存储的类,它本来是一个基于栈的C++对象,那么通常会使用 的构造函数。
如果你在 block 里面使用任何其他 C++基于栈的对象,它必须包含一个 const 的构造函数。该 C++对象使用该构造函数来拷贝。
4.3.3 Blocks
当你拷贝一个 block 时,任何在该 block 里面对其他 blocks 的引用都会在需要的 时候被拷贝,即拷贝整个目录树(从顶部开始)。如果你有 block 变量并在该 block 里 面引用其他的 block,那么那个其他的 block 会被拷贝一份。
当你拷贝一个基于栈的 block 时,你会获得一个新的 block。但是如果你拷贝一个 基于堆的 block,你只是简单的递增了该 block 的引用数,并把原始的 block 作为函数 或方法的返回值。

五章 使用Blocks
5.1 调用一个Block
如果你声明了一个 block 作为变量,你可以把它作为一个函数来使用,如下面的
两个例子所示:
int (^oneFrom)(int) = ^(int anInt) {

return anInt - 1;

};

printf("1 from 10 is %d", oneFrom(10));

// Prints "1 from 10 is 9"

float (^distanceTraveled) (float, float, float) =

^(float startingSpeed, float acceleration, float time) {

float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);

return distance;

};

float howFar = distanceTraveled(0.0, 9.8, 1.0);
// howFar = 4.9
然而你通常会把 block 作为参数传递给一个函数或方法。在这种情况下,你通过 需要创建一个”内联(inline)”的 block。
5.2 使用Block作为函数的参数
你可以把一个 block 作为函数的参数就像其他任何参数那样。然而在很多情况下, 你不需要声明blocks;相反你只要简单在需要它们作为参数的地方内联实现它们。下 面的例子使用 qsort_b 函数。qsort_b 和标准 qsort_r 函数类似,但是它最后一个参数用 block.
char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine"};

qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, constvoid *r) {

char *left = *(char **)l;

char *right = *(char **)r;

return strncmp(left, right, 1);

});

// Block implementation ends at "}"

// myCharacters is now { "Charles Condomine", "George", "TomJohn" }

注意函数参数列表包含了一个 block。
下一个例子显示了如何在 dispatch_apply 函数里面使用 block。dispatch_apply 声明 如下:
void dispatch_apply(size_t iterations, dispatch_queue_t queue, void(^block)(size_t));

该函数提交一个 block 给批处理队列来多次调用。它需要三个参数;第一个指定 迭代器的数量;第二个指定一个要提交 block 的队列;第三个是 block 它本身,它自 己需要一个参数(当前迭代器的下标)。
你可以使用 dispatch_apply 来简单的打印出迭代器的下标,如下:

#include

size_t count = 10;

dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(count, queue, ^(size_t i) {

printf("%u\n", i);

});

5.3 使用Block作为方法的参数
Cocoa 提供了一系列使用 block 的方法。你可以把一个 block 作为方法的参数就像 其他参数那样。
下面的例子确定数组前面五个元素中第一个出现在给定的过滤器集中任何一个 的下标。

NSArray *array = [NSArray arrayWithObjects: @"A", @"B", @"C", @"A",@"B", @"Z",@"G", @"are", @"Q", nil];

NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];

BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);

test = ^ (id obj, NSUInteger idx, BOOL *stop) {

if (idx < 5) {

if ([filterSet containsObject: obj]) {

return YES;

}

}

return NO;

};

NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];

NSLog(@"indexes: %@", indexes);

下面的例子确定一个 NSSet 是否包含一个由局部变量指定的单词,并且如果条件 成立把另外一个局部变量(found)设置为 YES(并停止搜索)。注意到 found 同时被声 明为__block 变量,并且该 block 是内联定义的:
__block BOOL found = NO;

NSSet *aSet = [NSSet setWithObjects: @"Alpha", @"Beta", @"Gamma",@"X", nil];

NSString *string = @"gamma";

[aSet enumerateObjectsUsingBlock:^(id obj, BOOL *stop) {

if ([obj :string] == NSOrderedSame) {

*stop = YES;

found = YES;

}

}];

// At this point, found == YES

5.4 拷贝Blocks
通常,你不需要 (或 retain)一个 block.在你希望 block 在它被声明的作用域 被销毁后继续使用的话,你子需要做一份拷贝。拷贝会把 block 移到堆里面。
你可以使用 C 函数来 和 release 一个 block:

Block_();
Block_release();
如果你使用 Objective-C,你可以给一个 block 发送 、retain 和 release(或 autorelease)消息。
为了避免内存泄露,你必须总是平衡 Block_()和 Block_release()。你必须平衡 或 retain 和release(或 autorelease)--除非是在垃圾回收的环境里面。
5.5 需要避免的模式
一个 block 的文本(通常是^{...})是一个代表 block 的本地栈数据结构地址。 因此该本地栈数据结构的作用范围是封闭的复合状态,所以你应该避免下面例子显示 的模式:
void dontDoThis() {

void (^blockArray[3])(void); // an array of 3 block references

for (int i = 0; i < 3; ++i) {

blockArray[i] = ^{ printf("hello, %d\n", i); };

// WRONG: The block literal scope is the "for" loop

}

}
void dontDoThisEither() {

void (^block)(void);

int i = random():

if (i > 1000) {

block = ^{ printf("got i at: %d\n", i); };

// WRONG: The block literal scope is the "then" clause

}

// ...
}
5.6 调试
你可以在 blocks 里面设置断点并单步调试。你可以在一个 GDB 的对话里面使用
invoke-block 来调用一个 block。如下面的例子所示:
$ invoke-block myBlock 10 20
如果你想传递一个 C 字符串,你必须用引号括这它。例如,为了传递 this string 给doSomethingWithString 的 block,你可以类似下面这样写:
$ invoke-block doSomethingWithString ""this string""
结束语
Block 是 iOS 4.0 之后添加的新特性支持。本人亲测感觉使用 Block 最大的便利就 是简化的回调过程。以前使用 UIView 的动画,进程要控制动画结束后进行相应的处 理。iOS 4.0 之后,UIView 新增了对 Block 的支持,现在只要使用简单的一个 Block 代码就可以在写动画的代码部分直接添加动画结束后的操作。还有就是在使用Notification 时候 Block 也非常有帮助。反正多用就可以体会到 Block的优美了。
对了,使用 Block 要谨记别造成对象互相引用对方导致引用计数进入一个循环导 致对象无法被释放。iOS 5.0 之后的 ARC 也是无法解决该潜在的互相引用的问题的。 所以写 Block 的时候要注意这点。因为 Block 往往在后台自动对一些它引用了的对象 进行 retain 操作。具体形式这里就不距离了,大家在使用的时候多体会一下。

❸ ios 类方法block怎么回调函数

其实,iOS中的Block就是C++中的函数指针,实现方式都是一样的,下面贴出一个简单的实践。

首先,创建一个回调的类

BlockStudy.h
//

// BlockStudy.m
// BlockStudy
//
// Created by 杜甲 on 11/11/14.
// Copyright (c) 2014 杜甲. All rights reserved.
//

#import "BlockStudy.h"

@implementation BlockStudy

- (void)test
{
if (_testBlock) {
_testBlock();
}
}

- (void)StartBlock
{
[self performSelector:@selector(test) withObject:nil afterDelay:2.0];
}

@end

调用类ViewController.m

//
// ViewController.m
// BlockStudy
//
// Created by 杜甲 on 11/11/14.
// Copyright (c) 2014 杜甲. All rights reserved.
//

#import "ViewController.h"
#import "BlockStudy.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
BlockStudy *block = [[BlockStudy alloc] init];
block.testBlock = ^()
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Block学习" message:@"测试成功" delegate:self cancelButtonTitle:@"取消吧" otherButtonTitles:@"OK", nil];
[alert show];

};
[block StartBlock];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}

@end

❹ ios block回调在哪个线程

block 返回之前在哪个线程 返回过后还是在哪个线程 没有线程的跳转

❺ iOS回调传值之block和delegate的区别

首先两者作用都进行单调
通delegate象用象自调用代理协议函数完整流程
block传递函数指针利用函数指针执行进行调
内存管理需要注意delegate需要保存引用block引用数据处理

❻ 网络层的回调为什么不建议使用Block

1.block很难追踪,难以维护
我们在调试的时候经常会单步追踪到某一个地方之后,发现版尼玛这里有个block,如果想权知道这个block里面都做了些什么事情,这时候就比较蛋疼了。

2.block会延长相关对象的生命周期
block会给内部所有的对象引用计数加一,这一方面会带来潜在的retain cycle,不过我们可以通过Weak Self的手段解决。另一方面比较重要就是,它会延长对象的生命周期。

在网络回调中使用block,是block导致对象生命周期被延长的其中一个场合,当ViewController从window中卸下时,如果尚有请求带着block在外面飞,然后block里面引用了ViewController(这种场合非常常见),那么ViewController是不能被及时回收的,即便你已经取消了请求,那也还是必须得等到请求着陆之后才能被回收。
然而使用delegate就不会有这样的问题,delegate是弱引用,哪怕请求仍然在外面飞,,ViewController还是能够及时被回收的,回收之后指针自动被置为了nil,无伤大雅。

❼ block的嵌套调用方式,2个block怎么相互嵌套

Block 变量拥有 blocks 的引用。你可以使用和声明函数指针类似的语法来声明它 们,除了它们使用^修饰专符来替代 * 修饰符。属Block 类型可以完全操作其他 C 系统 类型。以下都是合法的 block 声明: void (^)(void)...

❽ 网络请求中的block成功回调是怎么回调的 求代码

main()
{
int a,b,c;
a=5; b=6; c=7;
printf(“ ab c\tde\rf\n”);
printf(“hijk\tL\bM\n”);
}
3.5.3 字符变量
字符变量用来存储字符常量,即单个字符。内
字符变量的类型说明符是容char。字符变量类型定义的格式和书写规则都与整型变量相同。例如:
char a,b;
3.5.4 字符数据在内存中的存储形式及使用方法
每个字符变量被分配一个字节的内存空间,因此只能存放一个字符。字符值是以ASCII码的形式存放在变量的内存单元之中的。
如x的十进制ASCII码是120,y的十进制ASCII码是121。

❾ CAD:用BLOCK命令建立的图块,只能插入到生成它的图形文件中吗

1、使用BLOCK做的块是保存在当前图纸当中,如果在其他图纸中想调用这个块回,可以打开设答计中心(ADC),在文件夹列表中找到之前的图纸,然后点图纸名前面的“+”号,双击块,即可显示该图纸中所有的块,在右侧找到需要的块,然后鼠标左键点在块上,安装鼠标左键不松,拖动到绘图区域,然后按命令行提示,输入插入比例即可。

❿ block+Gcd 异步请求 在block回调里 刷新UI 为什么实现不了

您好,很高兴能帮抄助您
原因是我在 .h文件中声明 block 变量时
@property(nomaric,assign) 定义的block类型 变量名;
中你可以看到我用了 assign,导致我在调用的 可能已经被释放掉。
你可以查查 在使用block 做属性申明时 ,。最好使用 但使用retain 也是可以的。。
希望能帮到你

阅读全文

与用block保存异步回调的数据相关的资料

热点内容
反渗透膜推力架 浏览:626
档案室净化器怎么使用 浏览:212
污水处理排污许可 浏览:6
蒸汽熨斗自动除垢有用吗 浏览:962
如何处理含硫酸根的废水 浏览:1
污水在线PH监测仪 浏览:379
自来水厂反渗透膜中标 浏览:312
生活污水排放试验压力是多少 浏览:713
凝胶过滤NaCl 浏览:304
医疗废弃物无污水处理的情况说明 浏览:408
05老宝来汽油滤芯在哪里 浏览:213
水垢是晶体 浏览:917
辽阳自来水厂生产废水如何处理 浏览:963
洗碗厂污水设备多少钱 浏览:832
滤芯器什么牌子好 浏览:392
电流互感器如何提升精度 浏览:701
自己清洗ro膜 浏览:565
一体式净水器滤芯有什么区别 浏览:3
大话西游2男鬼用什么武器回血最好 浏览:312
如何选择饮水器滤芯的规格 浏览:875