IOS中block的一些用法

__weak typeof(self) weakSelf = self的应用

typeof(xxx)是用来确定括号中内容的类型,如

int a = 10;

可以这样写

typeof(100) a = 10;

这两种写法是等价的。那么回到上边,__weak typeof(self) weakSelf 可以用其它代码代替。假如self为PersonViewController,那么

__weak PersonViewController *weakSelf = self;

这两种也是等价的,只不过用typeof不用管那么多。

意思是声明了一个self类型的weakSelf,加上__weak表示它是弱引用的。整行代码就是给self定义了一个弱引用性质的替身。
一般用在block上,因为block会copy它内部的变量,可能会造成循环引用,使用__weak性质的self代替self,可以切断block对self的应用,避免循环使用。如

 1 if (nil == error) {
 2     __weak typeof(self) weakSelf = self;
 3     dispatch_async(dispatch_get_global_queue(0, 0), ^{
 4         /*异步解析*/
 5         NSArray  *array = EncodeArrayFromDic(jsonItems,@"data");
 6                 
 7         NSMutableArray *arrayDtos = [NSMutableArray array];
 8         for (NSDictionary *item in array) {
 9             DocMsgModel *dto = [DocMsgModel parser:item];
10             if (nil != dto) {
11                 [arrayDtos addObject:dto];
12             }
13         }
14                 
15         dispatch_async(dispatch_get_main_queue(), ^{
16             [weakSelf.delegate manageMainView];
17         });
18     });
19 }

 

block可以把函数当做属性来声明,虽然也可以直接在.h中写方法,这两种写法作用是一样的,只是写法不同。如下
在TableCell.h中

1 @property (nonatomic,strong) UIView *cellDownBg;
2 @property (nonatomic,copy) void(^deleteBtnClickBlock)(NSString *contentID);
3 //该block写法和下边的作用一样
4 //-(void)deleteBtnClick:(NSString *)contentId;

然后使用block时还需设置self(指的是controller)为weak型
在controller的.m中,

1 -(void)someFunction{
2     __weak typeof(self) weakSelf = self;
3     TableCell *cell = [[TableCell alloc] init];
4     cell.deleteBtnClickBlock = ^(NSString *contentID){
5         [weakSelf deleteContentWithContentId:contentID];
6     }
7 }

 

下面说下block比较详细的用法

第一部分:block形式
block有三种形式,关于参数和返回值的。
①无参数,无返回值

-(void)viewDidLoad {
    [super viewDidLoad];

    void(^printSth)() = ^(){
        printf("没有数字
");
    }
    printSth();
}

打印结果为:

②有参数,无返回值

-(void)viewDidLoad {
    [super viewDidLoad];

    printTheNum(55);
}

void(^printTheNum)(int) = ^(int val){
    printf("the num is %d 
",val);
};

打印结果为:

③有参数,有返回值

-(void)viewDidLoad {
    [super viewDidLoad];

    int localNum = 7;
    int (^printElse)(int) = ^(int num){
        return num * localNum;
    };

    int newNum = printElse(3);
    printf("new localNum is %d 
",newNum);
}

打印结果为:

由上可以看出,block既可以定义在方法(如viewDidLoad)内部,也可以定义在方法外部。

第二部分:__block关键字的使用
在block的{}内,是不可以对外面的变量进行赋值的。如:

1 - (void)viewDidLoad {
2     [super viewDidLoad];
3 
4     int localNum = 7;
5     int (^myBlock)(int) = ^(int num){
6         localNum = num * 3;
7         return num * localNum;
8     };
9 }

此时会有Variable is not assignable (missing __block type specifier)的错误提示。

加上__block,就可以修改了。

第三部分:不同类间的传值
block作用如同函数,当用作property时,可以在两个类之间传值。如:
两个controller,分别为A和B,A中有label,B中有textfield。当跳往B后,点击按钮再返回A。label显示textfield的内容。
①用delegate实现
在B的.h中

@protocol ThirdViewControllerDelegate <NSObject>

@optional
-(void)transferTheVal:(NSString *) textVal;

@end

@interface ThirdViewController : UIViewController

@property(nonatomic,assign) id<ThirdViewControllerDelegate> delegate;

@end

在B的.m中

-(void)clickTheBtn{
    [self.navigationController popViewControllerAnimated:YES];
    
    if (self.delegate && [self.delegate respondsToSelector:@selector(transferTheVal:)]) {
        [self.delegate transferTheVal:self.textFirldAll.text];
    }
}

在A的.m中

@interface ViewController ()<ThirdViewControllerDelegate>
@property(nonatomic,strong) UILabel *myLab;
@end

-(void)transferTheVal:(NSString *)textVal{
    self.myLab.text = textVal;
}

②用block实现
在B的.h中

@interface NextViewController : UIViewController

@property(nonatomic,strong) UITextField *textFirldAll;

@property(nonatomic,copy) void(^nextControlBlock)(NSString *textVal);

@end

在B的.m中

-(void)clickTheBtn{
    [self.navigationController popViewControllerAnimated:YES];
    
    if (self.nextControlBlock) {
        self.nextControlBlock(self.textFirldAll.text);
    }
}

在A的.m中

 1 -(void)clickTheBtn{
 2     NextViewController *nextVC = [[NextViewController alloc] init];
 3     [self.navigationController pushViewController:nextVC animated:YES];
 4     __weak typeof(self) weakSelf = self;
 5     //block中应为weak型的self,防止循环引用
 6     nextVC.nextControlBlock = ^(NSString *textVal){
 7         [weakSelf resetTextVal:textVal];
 8     };
 9 }
10 
11 -(void)resetTextVal:(NSString *)newVal{
12     self.myLab.text = newVal;
13 }

由此可以看出delegate和block两种用法的异同

 

************************** 2015-10-08 补充 **************************

block也可以在函数中使用,作为参数类型。

//参数为changed,类型为void(^)(void)
- (void)doSth:(void(^)(void))changed;
//参数squre的类型为int(^)(int)型
-(void)objcMethod:(int(^)(float))squre;

使用时有

- (void)doSth:(void(^)(void))changed{
    //其它的其它操作
    //执行block
    changed();
}

-(void)objcMethod:(int(^)(float))squre{
    squre(3.0);
}

void(^)(void)表示无参数无返回值,int(^)(float)表示参数为float,返回值为int

由这两种写法可以看出,当block作为参数类型时,代码格式---中间的(^)是必须的

使用block需要注意的问题

①在调用block时必须做非空判断,否则会崩溃

void (^logPrint)() = ^{
    NSLog(@"*********");
};

if (nil != logPrint) {
    logPrint();
}

②对于比较长的block,尽量用typedef定义新的名称来代替block。typedef的用法如下:

typedef int MyInt;
//与int a = 10 等价
MyInt a = 10;

意为将int类型用MyInt代替,这样比较直观。对于block类型,写法不太一样。

//两数相加
int(^plusNum)(int,int) = ^(int a,int b){
    return a+b;
};

//两数相减
int(^minusNum)(int,int) = ^(int a,int b){
    return a-b;
};

用typedef重新定义

typedef int(^twoNum)(int num1,int num2);

表示返回值为int类型,参数有两个,且都为int类型,block名称为twoNum。
使用时可以

-(void)viewDidLoad{
    [super viewDidLoad];

    //两数相加
    twoNum plusNu = ^(int a,int b){
        return a + b;
    };
    
    //两数相减
    twoNum minusNu = ^(int a,int b){
        return a - b;
    };
    
    plusNu(4,2);
    minusNu(3,5);
}

对于对象类型的block,有参数有返回值的写法

NSString * (^myName)(NSString *a,NSString *b) = ^(NSString *firstName,NSString *lastName){
    NSString *name = [firstName stringByAppendingString:lastName];
    NSLog(@"my Name is %@",name );
    return name;
};

用typedef定义时

typedef NSString * (^MyName) (NSString *firstName,NSString *lastName);
-(void)viewDidLoad{
    [super viewDidLoad];

    MyName nameL = ^(NSString *firstName,NSString *lastName){
        NSString *name = [firstName stringByAppendingString:lastName];
        NSLog(@"----%@",name);
        return name;
    };
    nameL(@"Xi",@"Li");
}

可以看出,作用一样,只是形式上更简洁。尽量使用typedef这种写法。

*********** 2016-04-12补充  *****************

block作为代码块,可以用在属性、方法中。示例如下:

#pragma mark —— block作为属性

//无参数,无返回值
@property(nonatomic,copy) void(^test1)();
//无参数,有返回值
@property(nonatomic,copy) NSString *(^test2)();
//有参数,有返回值
@property(nonatomic,copy) NSString *(^test3)(NSString *firstName,NSString *lastName);

#pragma mark —— block作为方法的参数

//无参数,无返回值
-(void)testOne:(void(^)()) testBlock;
//无参数,有返回值
-(void)testTwo:(NSString *(^)()) testBlock;
//有参数,有返回值
-(void)testThree:(NSString *(^)(NSString *num1,NSString *num2)) testBlock;
原文地址:https://www.cnblogs.com/Apologize/p/4775830.html