玩转 IOS 开发 - block 使用详解

Block 是iOS在4.0之后新增的程式语法,在iOS SDK 4.0之后,block应用几乎无处不在。

在其他语言中也有类似的概念称做闭包(closure),比如object C的好兄弟swift 中闭包(swift 闭包详解)的使用跟 OC的block一样重要。总的来说:

Block是C语言的
Block是一个数据类型
Block 是一个提前准备好的代码,在需要的时候执行

1. block作用:

Block用来封装一段代码,可以在任何时候执行;

  • Block可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。
  • 苹果官方建议尽量多用block。在多线程、异步任务 、集合遍历、集合排序、动画转场用的很多

在新的iOS API中block被大量用来取代传统的delegate和callback,而新的API会大量使用block主要是基于以下两个原因:

A. 可以直接在block代码块中写等会要接着执行的代码,直接把block变成函数的参数传入函数中,这是新API最常使用block的地方。

B. 可以存取局部变量,在传统的callback操作时,若想要存取局部变量得将变量封装成结构体才能使用,而block则是可以很方便地直接存取局部变量。

2. Block的定义:

定义时,把block当成数据类型

特点:
1. 类型比函数定义多了一个 ^
2. 设置数值,有一个 ^,内容是 {} 括起的一段代码

(1)基本定义方式

/*
*1.最简单的定义方式:
*格式:void (^myBlock)() = ^ { // 代码实现; }
*/
void (^myBlock)() = ^ {
    NSLog(@"hello");
};

// 执行时,把block当成函数
myBlock();

/*
*2.定义带参数的block:
*格式:void (^block名称)(参数列表) = ^ (参数列表) { // 代码实现; }
*/
void (^sumBlock)(int, int) = ^ (int x, int y) {
    NSLog(@"%d", x + y);
};

sumBlock(10, 20);

/*
*3.定义带返回值的block
*格式:返回类型 (^block名称)(参数列表) = ^ 返回类型 (参数列表) { // 代码实现; }
*/
int (^sumBlock2)(int, int) = ^ int (int a, int b) {
    return a + b;
};

NSLog(@"%d", sumBlock2(4, 8));

(2) block 指针

Block Pointer是这样定义的:

回传值 (^名字) (参数列);

//声明一个名字为square的Block Pointer,其所指向的Block有一个int输入和int输出  
int (^square)(int);  

//block 指针square的内容
square = ^(int a){ return a*a ; };  

//调用方法,感觉是是不是很像function的用法?  
int result = square(5);  
NSLog(@"%d", result);  

(3) 用typedef先声明类型,再定义变量进行赋值

typedef int (^MySum)(int,int);
MySum sum = ^(int a,int b)
 { 
      return a + b;
};

(4) block 访问外部变量

但是block使用有个特点,Block可以访问局部变量,但是不能修改:

int sum = 10;

int (^MyBlock)(int) = ^(int num) 
{ 
     sum++;//编译报错 
     return num * sum; 
};

如果要修改就要加关键字 __block (下面详细说明):

__block int sum =10;

(5) block 与函数指针

下面比较下函数指针与block异同:

  • 定义函数指针 int (*myFn)();
    调用函数指针 (*myFn)(10, 20);

  • 定义Block int (^MyBlocks)(int,int);
    调用Blocks MyBlocks(10, 20);

3. block访问外部变量

block 访问外部变量有几个特点必须知道:

  • block内部可以访问外部变量;
  • 默认情况下block内部不能修改外面的局部变量;
  • 给局部变量加上关键字_block,这个局部变量就可以在block内部修改;

block中可以访问外部变量。但是不能修改它,否则编译错误。但是可以改变全局变量、静态变量(static)、全局静态变量。

上面的特点是有原因滴:

A. 为何不让修改变量:这个是编译器决定的。理论上当然可以修改变量了,只不过block捕获的是外部变量的副本,名字一样。为了不给开发者迷惑,干脆不让赋值。道理有点像:函数参数,要用指针,不然传递的是副本(大家想起那个经典的两个数调换值的问题了吧)。

B. 可以修改静态变量的值。静态变量属于类的,不是某一个变量。所以block内部不用调用cself指针。所以block可以调用。

(1) __block存储类型

通过__block存储类型修饰符, 变量在block中可被修改。__block存储跟register、auto和static存储类型相似(但是之间互斥),用于局部变量。__block变量存储在堆区,因此,这个block使用的外部变量,将会在栈结束被留下来。

从优化角度考虑,block存储在栈上,如果block被拷贝(通过Block_copy或者copy),变量被拷贝到堆。因此__block变量的地址就会改变。

__block变量还有两个限制,他们不能是可变数组(NSMutableArray),不能是结构体(structure)。

__block 变量的内部实现要复杂许多,__block 变量其实是一个结构体对象,拷贝的是指向该结构体对象的指针

(2) block访问外部变量

上面已经说过,默认block 访问的外部变量是只读属性的,若要对外部变量进行读写,需要在定义外部变量时加一个 __block, 示例如下:

//示例1:block访问外部变量
void demoBlock1() 
{
    int x = 
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
iOS开发中上传图片可以采用以下步骤: 1.选择要上传的图片,可以使用系统提供的UIImagePickerController控制器,或者使用第三方库,例如TZImagePickerController。 2.将选中的图片转换为NSData格式。 3.使用NSURLSession或AFNetworking等网络库,将图片数据上传到服务器。 以下是一个简单的上传图片的示例代码: ``` // 选择图片 UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary; imagePicker.delegate = self; [self presentViewController:imagePicker animated:YES completion:nil]; // 将选中的图片转换为NSData格式 - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<UIImagePickerControllerInfoKey,id> *)info { UIImage *selectedImage = info[UIImagePickerControllerOriginalImage]; NSData *imageData = UIImageJPEGRepresentation(selectedImage, 0.5); // 上传图片到服务器 NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; NSURL *url = [NSURL URLWithString:@"http://example.com/upload.php"]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = @"POST"; NSURLSessionUploadTask *uploadTask = [session uploadTaskWithRequest:request fromData:imageData completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { // 处理服务器返回的响应 }]; [uploadTask resume]; [picker dismissViewControllerAnimated:YES completion:nil]; } ``` 其中,upload.php是服务器端接收图片的脚本文件。在服务器端,可以使用PHP等语言来处理上传的图片数据。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值