文档章节

iOS——Block笔记

kinglin_fu
 kinglin_fu
发布于 2016/01/13 11:41
字数 1841
阅读 105
收藏 1

1、block的基本概念和语法                                                            

  • 基本概念

    block叫代码块、闭包或者匿名函数。包含返回值类型、block标记、名称、参数和主体,类似C语言的函数。它本质上是可移植的匿名函数,可作为方法和函数的参数传入,或可从方法和函数中返回。

  • 语法结构

    返回类型(^名称)(参数...) = ^(参数) { 主体... };


   /*例子:这是一个返回值类型为 int 名称为fristBlock 带有一个int类型参数的block。*/
    
    int (^fristBlock)(int) = ^(int a) {
        
        int b = a + 200;
        return b;
    };

  • Apple所推荐的block使用范围包括以下几个方面:

    排序 ——在block内写排序算法

    View动画 ——简单明了的方式规定动画

    完成处理 ——当方法执行完毕后执行block代码

    枚举 ——通过block获取枚举对象或控制枚举进程

    通知 ——当某事件发生后执行block内的代码

    错误处理 ——当错误发生时执行block代码

    GCD多线程 ——多线程控制

2、block的简单使用                                                                            

  •   block也叫匿名函数,所以用法类似C语言函数。两步:实现和调用


/*1、实现block*/
int b = 100;
void (^myBlock)(int a) = ^(int a) {
  
    // block 主体
    int c =  a + b;
    NSLog(@"c = %d",c);
};
    
/*2、调用block:block中的代码必须调用才能起作用,类似c函数的调用*/
myBlock(200);	// 调用block


3、block作为参数使用                                                                                         

  •   block作为一个代码块可以被用来作为方法或者函数的参数。


*/ 调用方法*/
[self blockMethod:^(int a, int b) {

    NSLog(@"a + b = %d",a + b);
 }];

/*定义一个以block为参数的方法*/
- (void)blockMethod:(void(^)(int a,int b)) block {

    block(100,200); // 调用
}


4、使用typedef定义block                                                                 

  • 由于block的语法不是很简洁,直接使用不是很方便。所以我们使用时通常使用typedef关键字来定义block,达到使用的方便简洁。


/*使用typedef定义一个没有返回值带有两个int参数的block类型名称为TestBlock,后面就可以直接使用TestBlock定义对应的block变量了*/

typedef void(^TestBlock)(int a, int b);

/*1.定义一个类型为TestBlock的block。*/
TestBlock tBlock = ^(int a, int b){
        
    NSLog(@"a + b = %d",a + b);
};
tBlock(200,300);

/*2.使用TestBlock类型的block作为参数*/
- (void)blockMethodTypedef:(TestBlock)block
{
    if(block) {
        block(100,200);
    }
}

/*3.使用TestBlock类型的block作为返回值*/
- (TestBlock)returnBlockMethodTypedef
{
    return ^(int a, int b){
       
        NSLog(@"output two number %d and %d",a, b);
    };
}


5、block作为属性使用                                                                        

  • block代码块可以作为类的属性使用,使用copy关键字修饰


/*>> .h文件中定义*/
typedef int(^SumBlock)(int a, int b);

@property(nonatomic, copy)SumBlock block;

/*>> .m文件中实现\调用*/
/*1、实现block*/
self.block = ^(int a,int b) {

    return a + b;
};
/*2、调用block,调用时先判断block不为nil再调用。因为block有可能没实现*/
if (self.block) {

    int sum = self.block(100,200)    
    NSLog(@"sum = %d",sum );
}


6、block访问使用局部变量                                                                  

  • block内部可以使用外部的局部变量,但是不能修改。如果要想修改得使用__block关键字修饰变量。


/*例1. 访问外部变量 */
    int num = 100;
    int(^numBlock)(int) = ^(int a){

        int result = num + a;
        // num += 100; 错误:block内只能访问使用外部普通变量,但是不能修改。
        return result;
    };
    num = 0;
    NSLog(@"num = %d",num); // num = 0
    NSLog(@"numBlock = %d",numBlock(200));   // numBlock = 300

    
/*例2. 修改外部变量*/
   __block int var = 100;         // block变量
    int(^varBlock)(int) = ^(int a){

        var += a;                 // __block标记的变量block内部可以修改
        return var;
    };
    var = 0;
    NSLog(@"var = %d",var); // var = 0
    NSLog(@"varBlock = %d",varBlock(200)); // varBlock = 200

  • 如上打印结果,numBlock = 300, varBlock = 200;

  • 解析:

    block使用外部普通局部变量时是将变量的值拷贝一份到block中,也就是说block内的num不再是原来同一个num了,所以后面修改num的值不会影响block中num。

    使用__block修饰的变量在block中使用时不会进行拷贝,使用的是同一个。所以后面修改var的值会影响block中的var。

5、block内存管理                                                                              

  • block的类别:三种类型的block

    1. NSGlobalBlock 全局区的block,没有使用任何外部变量的block

    2. NSStackBlock 栈区的block,使用了外部局部变量的block

    3. NSMallocBlock 堆区block,使用copy或Block_copy()拷贝后block就保持到了堆区中,需要管理内存。

  • block的拷贝:(MRC下)

    1. 使用copy或Block_copy()是将栈区的block拷贝到堆区中,引用计数不会+1。

    2. block被拷贝后会对使用到的外部局部变量对象引用计数+1,但是全局变量、实例变量、静态变量、__block变量引用计数不会+1。

    3. block内使用了实例变量不会对实例引用计数+1,但是会对实例变量持有者应用计数+1。

    4. MRC下需要手动使用copy或者Block_copy()将block拷贝到堆区中,然后内存自己管理,使用Block_release()对应引用计数-1。

    5. ARC下不需要手动copy,当block使用了局部变量后会自动拷贝到堆区中,也就是说ARC下不需要手动对block进行copy和release。

  • 例1:block内使用的对象的引用计数。


  static NSObject *staticObj = nil;
  _instanceObj = [[NSObject alloc] init];  //  实例变量
  globalObj = [[NSObject alloc] init];     //  全局变量
  staticObj = [[NSObject alloc] init];     //  静态变量

  NSObject *localObj = [[NSObject alloc] init]; // 局部变量
  __block NSObject *blockObj = [[NSObject alloc] init]; // __block变量

  self.block = ^{

      NSLog(@"%@",[_instanceObj retainCount]); // 1
      NSLog(@"%@",[globalObj retainCount]);    // 1
      NSLog(@"%@",[staticObj retainCount]);    // 1
      NSLog(@"%@",[localObj retainCount]);     // 2
      NSLog(@"%@",[blockObj retainCount]);     // 1
  };

  if (self.block) {

      _block();
  }

  • 例2:MRC下对block的拷贝


  int value = 100;
  void(^block)(int) = ^(int var){

      NSLog(@"result:%d",value + var);
  };
  NSLog(@"%@",block);         //<__NSStackBlock__: 0x7fff51896988>

  NSLog(@"引用计数:%ld",[block retainCount]); // 1

  /* 使用copy或者Block_copy()把栈区的block拷贝到堆区,引用计数不会改变。*/
  void(^mallocBlock)(int) = Block_copy(block);
  //void(^mallocBlock)(int) = [block copy];
  mallocBlock(200);

  NSLog(@"%@",mallocBlock);   // <__NSMallocBlock__: 0x7fa0ca617d10>
  NSLog(@"引用计数:%ld",[mallocBlock retainCount]); // 1

  Block_release(mallocBlock); //堆区的block需要管理内存。


6、block的循环引                                                                    

  • 描述:

    当一个对象持有了block后,block内部又使用了这个对象或者对象的实例变量、实例方法,这样会使block也持有这个对象,这样相互持有就是循环引用,从而导致对象无法释放引起内存泄露。

  • 解决:

    要解决循环引用只需要不要相互持有就行了,也就是说只需要一方持有就可以不让block再持有当前这个对象就OK。


  /*循环引用:self持有block,block又持有了self。*/
  self.block = ^{

      self.info = @"这里会有循环引用";  // block内部使用了self得实例变量会retain self
      [self testMeethod];

  };


  /*1. MRC下解决循环引用:不要在block内部直接使用self,要使用__block修饰的self,这样block内部就不会对self retain了。*/
  __block typeof(self)blockSelf = self;
  self.block = ^{

      blockSelf.info = @"这样就没有循环引用了";
      [_blockSelf testMethod];    

  };

  /*2. ARC下解决循环引用:使用__weak修饰self后,block就不会再持有self了。*/
  __weak typeof(self)weakSelf = self;
  self.block = ^{

      weakSelf.info = @"这样就不会循环引用了";
      [weakSelf testMethod];
  };

  /*实例方法*/
  - (void)testMethod
  {
   NSLog(@"测试方法!");
  }


7、block实践使用Demo(传值 、事件处理)                               

Demo地址:https://github.com/fuqinglin/block-     

参考:

1、 http://blog.csdn.net/yin_xianwei/article/details/17998165


2、https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Blocks/Articles/bxGettingStarted.html                                                                                                                                                                  

© 著作权归作者所有

kinglin_fu
粉丝 16
博文 11
码字总数 14320
作品 0
石景山
私信 提问
开源高仿印象笔记的iOS应用——朝夕笔记(Oncenote)

这是一款类似于印象笔记Evernote的生活类iOS应用——朝夕笔记 Oncenote。我希望能为更多的iOS开发者提供帮助与服务。当然App中还有不少bug和可扩展的功能模块,也希望各位开发者为该项目贡献...

503434355
2015/11/23
3.1K
1
UIView Animations 学习笔记(一)简介及API说明

目录 UIView Animations 学习笔记(一)简介及API说明 UIView Animation 学习笔记 应用示例 一、简介 随着iOS7的发布,动画与运动效果变成了Apple和第三方开发者进行app设计的中心。iOS7介绍...

灰大羊
2015/08/01
0
0
OSC 第 63 期高手问答 —— iOS 开发进阶

OSCHINA 本期高手问答( 3月17日- 3月21日)我们请来了@唐巧 为大家解答关于 iOS 开发 方面的问题。 @唐巧 ,Blogger、InfoQ 编辑,资深 iOS 开发者。曾在网易参与过网易邮箱、网易微博、有道云...

叶秀兰
2015/03/17
3.5K
39
2018 iOS 面试题大全(补充完整版)

原文地址:2018 iOS 面试题大全 由于原作者并没有继续更新,这里我转过来继续更新下 这个栏目将持续更新--请iOS的小伙伴关注! 1、iOS 应用导航模式有哪些? 2、iOS 中持久化方式有哪些? 3、...

Theendisthebegi
2018/11/15
0
0
唐巧专访:用 HTML5 写移动应用终究不会成为主流

小编语 本文为 DevLink 专访系列,本期采访嘉宾是 iDev 苹果开发者大会特约出品人、小猿搜题产品技术负责人——唐巧。在参加 iDev 苹果开发者大会前夕,这位资深 iOS 开发者接受了 DevLink ...

DevLink
2016/10/13
270
0

没有更多内容

加载失败,请刷新页面

加载更多

Protocol Buffers 简介

文档编辑和持续集成状态: 本文档的 Protocol Buffer 的中文文档使用的是 Asciidoctor 进行编排的 http://docs.ossez.com/protocol-buffers-docs/index.html(本 WIKI 中的内容将会与在线发布...

honeymoose
今天
4
0
uniapp + bootstrapvue 移动/PC 一套搞定 (一)配置bootstrapvue

1.准备文件 自己到DCloud官网: http://dcloud.io/ 去下载官方的IDE Hbuilder,新建一个空的uniapp项目即可。 uniapp框架自带优化的vue,我们仅仅需要准备以下三个文件: bootstrap.min.css ...

panyunxing
今天
11
0
Android Camera原理之camera service类与接口关系

camera service主要是指 frameworks/av/services/camera/下面的代码,最近在看这一块的代码,为了更好地理清这一块的代码,也为了后续学习camera方便一些,我觉得很有必要理一下这一块的整体...

天王盖地虎626
今天
6
0
Golang学习笔记

[TOC] Golang学习笔记 这个学习笔记是最早在1.初,版本左右的时候写的,和当前最新的版本可能会有较大的差异. 因为成文比较早,文章里面又有很多自己的见解,有些东西当时理解的不太透彻可能写错...

我爱吃炒鸡
今天
18
0
科技赋能成效显著!金融壹账通两大赋能项目荣获IDC大奖

7月19日,2019IDC中国未来金融论坛曁颁奖典礼于北京举办。由金融壹账通赋能的长春农商银行多人视频面审智能风控系统、包头农商银行互联网银行SaaS服务两大项目因在项目的创新性、技术领先性、...

IFTNews
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部