iOS开发

iOS基础之block

2016-05-16  本文已影响586人  ValienZh

1.block类型-存储代码块的类型

在异步编程时常需要进行函数回调,在C#中会用匿名委托或者lambda表达式讲一个操作作为参数进行传递.
ObjC中是使用对于闭包的实现,在块状中我们可以持有或引用局部变量. 同时利用Block可以将一个操作作为参数进行传递;

blcok用法:

例:

    int (^myBlcok)(int ,int)=^(int m,int n){
      return  m+n;
      }; //无参数时大括号前()可省略
      
      myBlock(10,5);    //调用块,省略了接受块返回值;

总结:经过简单了解C与OC;发现从最小的一个变量到表达式再到一个函数,其实只起两点作用: 值(返回值) 与 功能(行为,方法,作用).
所以说一行代码,按它是使用了值 还是 功能来解读比较容易理解.

Block做使用场景:

block传值的循环引用问题:

只有当block直接或间接的被self持有时,在block使用self时才需要替换为weak self。如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。

   __weak __typeof__(self) weakSelf = self;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        __strong __typeof(self) strongSelf = weakSelf;

        [strongSelf doSomething];

        [strongSelf doOtherThing];

    });

typedef block格式

类似函数指针,直接在定义格式之前加 typedef关键字,之后变量名就是类型的别名了.
typedef viod (^别名)(形参);
一般以后需要使用block作为函数方法的参数时,为方便最好用别名.而在block作用返回值时,一定需要别名,因为编译器不能识别做此时类型做何种解释.
延伸:经过测试,block在编译时按代码顺序,而运行时按调用顺序(变量作用域)

使用例子:
KCButton.h

#import <Foundation/Foundation.h>
@class KCButton;
typedef void(^KCButtonClick)(KCButton *);

@interface KCButton : NSObject

#pragma mark - 属性
@property (nonatomic,copy) KCButtonClick onClick;

#pragma mark 点击方法
-(void)click;
@end

KCButton.m

#import "KCButton.h"


@implementation KCButton

-(void)click{
    NSLog(@"Invoke KCButton's click method.");
    if (_onClick) {
        _onClick(self);
    }
}

@end

main.m

   KCButton *button=[[KCButton alloc]init];
    button.onClick=^(KCButton *btn){
        NSLog(@"Invoke onClick method.The button is:%@.",btn);
    };
    [button click];
    /*结果:
     Invoke KCButton's click method.
     Invoke onClick method.The button is:<KCButton: 0x1006011f0>.
     */

block访问外部变量

三种类型block

根据block在内存中的位置
"NSGlobaBlock"类似函数,存于代码区--全局block
"NNStackBlock"栈区,函数返回后的Block--栈
"NSMallocBlock"堆block--堆
  1. block内没有使用外部变量或是只使用了全局/静态变量时.存于全局代码区,为全局block;---(ARC和MRC下一致)
  2. 当使用外部变量时
    • MRC下,block代码存于栈区;如果此外部变量A存于区,那么A会被copy到block分配的区;如果A是存于区,那么A在block块内与快外相同.
    • ARC下,block代码存于堆区.如果此外部变量A存于区,那么A会被copy到block分配的区;如果A是存于区,那么A在block块内与快外相同.
  3. 如果需要修改外部变量,需要在变量前面声明__Block;
    当使用下划线Block修饰外部变量时:
    • MRC下,无论变量A存于还是区,A在block块内与快外相同;
    • ARC下,如果此外部变量A存于区,那么A会被转移而不是复制区;如果A是存于区,那么A在block块内与快外相同.

面试题:block的@property参数(内存管理参数)为什么要用copy:如果不用copy,此时不论ARC还是MRC都是栈Bolck,栈block会提前释放,导致无法继续使用;可以copy到堆区手动管理内存.(而字符串copy是防止字符串如果是非常量的,外部可变,造成非预估的结果;)

block在MRC下得内存隐患(NNStacKBlock)

Block_copy将block及内部变量拷贝到堆区.
使用完毕用Blok_release(block变量)释放此堆区空间;


block使用技巧

  1. block结构快速显示:inlineBlock...(也可右下角自定义快速显示其他格式)
  2. Block作为方法参数时,最好把参数列表部分加上,这样后面调用方法时,会自动有格式;
  3. 做方法参数时,需要加上返回值类型;
  4. 做返回值时,先定义别名,最后别忘记执行返回值;
  5. 方法中,void(^)()表示block类型同int,做参和返回值;做实例变量
    @property (nonatomic, copy) void(^变量名)()
  6. get点语法获取block类型实例变量时,自动执行,后面需加();
上一篇下一篇

猜你喜欢

热点阅读