block记录

Block使用详解

本文主要是阐述一下Block中如何的使用外部变量以及block本身的内存管理。

先定义一个block变量,作为后续的例子中使用:

typedef void(^BlockCC)(void); 
BlockCC _block; 

1、block中引用外部变量
block中可以直接使用外部的变量,比如

int number = 1; 
_block = ^(){ 
    NSLog(@"number %d", number); 
}; 

那么实际上,在block生成的时候,是会把number当做是常量变量编码到block当中。可以看到,以下的代码,block中的number值是不会发生变化的:

int number = 1; 
_block = ^(){ 
    NSLog(@"number %d", number); 
}; 
number = 2; 
_block(); 

则输出的值为 1,而不是2。原因就是如上所说。

如果要在block中尝试改变外部变量的值,则会报错的。对于这个问题的解决办法是引入__block标识符。将需要在block内部修改的变量标识为__block scope。更改后的代码如下:

__block int number = 1; 
_block = ^(){ 
    number++; 
    NSLog(@"number %d", number); 
}; 

而这个时候,其实block外部的number和block内部的number指向了同一个值,回到刚才的在外部改变block的例子,它的输出结果将是2,而不是1。有兴趣的可以自己写一个例子试试。

以上是针对自动变量(局部变量情况),当变量为全局变量,静态变量,全局静态变量时,block内部是可以对变量进行赋值修改的。

2、block自身的内存管理
block本身是像对象一样可以retain,和release。但是,block在创建的时候,它的内存是分配在栈(stack)上,而不是在堆(heap)上。他本身的作于域是属于创建时候的作用域,一旦在创建时候的作用域外面调用block将导致程序崩溃。比如下面的例子。
我在view did load中创建了一个block:

- (void)viewDidLoad 
{ 
    [superviewDidLoad]; 

    int number = 1; 
    _block = ^(){ 

    NSLog(@"number %d", number); 
}; 
} 

并且在一个按钮的事件中调用了这个block:

- (IBAction)testDidClick:(id)sender { 
    _block(); 
} 

此时我按了按钮之后就会导致程序崩溃,解决这个问题的方法就是在创建完block的时候需要调用copy的方法。copy会把block从栈上移动到堆上,那么就可以在其他地方使用这个block了~
修改代码如下:

_block = ^(){ 
    NSLog(@"number %d", number); 
}; 

_block = [_blockcopy];
同理,特别需要注意的地方就是在把block放到集合类当中去的时候,如果直接把生成的block放入到集合类中,是无法在其他地方使用block,必须要对block进行copy。不过代码看上去相对奇怪一些:

[array addObject:[[^{ 
    NSLog(@"hello!"); 
} copy] autorelease]]; 

3、循环引用
这一点其实是在第一点的一个小的衍生。当在block内部使用成员变量的时候,比如

@interface ViewController : UIViewController 
{ 
    NSString *_string; 
} 
@end 
在block创建中:

_block = ^(){ 
    NSLog(@"string %@", _string); 
}; 

这里的_string相当于是self->_string;那么block是会对内部的对象进行一次retain。也就是说,self会被retain一次。当self释放的时候,需要block释放后才会对self进行释放,但是block的释放又需要等self的dealloc中才会释放。如此一来变形成了循环引用,导致内存泄露。

修改方案是新建一个__block scope的局部变量,并把self赋值给它,而在block内部则使用这个局部变量来进行取值。因为__block标记的变量是不会被自动retain的。

__block ViewController *controller = self; 
_block = ^(){ 
    NSLog(@"string %@", controller->_string); 
}; 
### Block在编程中的含义和用法 #### 区块链上下文中的Block 在区块链技术领域,`block`通常指代构成区块链的基本单元。每个区块包含了若干交易记录和其他元数据。具体来说,在智能合约环境中获取当前区块信息可以通过定义一个名为 `get_block_info()` 的函数实现: ```solidity contract BlockInfo { function getBlockInfo() public view returns (uint, uint, uint, address) { return ( block.number, block.timestamp, block.difficulty, block.coinbase ); } } ``` 上述代码展示了如何在一个 Solidity 合约中创建一个可以查询当前区块详情的方法[^1]。 #### NumPy 中的block 方法 对于 Python 编程语言而言,特别是在处理数值运算时经常使用的库——NumPy 提供了一个叫做 `block` 的方法。此方法主要用于构建由其他数组组成的大型数组结构。下面是一个简单的例子来说明其基本用途: ```python import numpy as np arr = np.block([ [np.array([1, 2]), np.array([3])], [np.eye(2), [[4]]] ]) print(arr) ``` 这段脚本会输出如下矩阵: ``` [[1. 2. 3.] [0. 1. 4.]] ``` 这里利用了 `block` 函数将几个不同的子阵列拼接在一起形成一个新的二维数组[^2]。 #### Linux 网络编程中的非阻塞连接尝试 当涉及到操作系统层面的操作时,“block”也可能指的是程序执行过程中是否会暂停等待某个事件的发生。例如在网络通信场景下建立TCP连接的过程中可以选择采用非阻塞模式来进行快速失败检测: ```c int connect_nonblock(const char *lpIP, int nPort){ int err = -1; socklen_t len = sizeof(err); // ...省略部分初始化套接字并设置为非阻塞模式的代码... if(connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr))<0){ if(errno==EINPROGRESS){ printf("Non-blocking connection attempt started.\n"); return 0; /* 连接正在尝试 */ }else{ perror("connect error"); close(sockfd); return -1; } } // 成功立即返回或进一步处理已完成的连接... } ``` 在这个 C 语言片段里,通过调用 `connect()` 并配合特定错误码判断实现了异步发起网络请求的功能[^3]。 综上所述,尽管都涉及到了“block”,但在不同语境和技术栈之间其实有着截然不同的意义与应用场景。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值