block

定义

inlineBlock

return_value ^(block_name)(arg_list) = return_value ^(arg_list){
	code_block;
}

typedef Block

  • block是一种数据类型,可以定义类型,当作返回值

typedefBlock.m

#import <Foundation/Foundation.h>
typedef void^(myBlock)();
myBlock myDemo(){
	myBlock mb = ^{
		NSLog(@"test");
	}
	return mb;
}
int main(){
	myBlock mb = myDemo();
	mb();
	return 0;
}

循环引用问题

  • block在定义时会默认对外部变量做一次copy(强引用)

  • 在Obj-C中定义指针变量默认都是strong类型,可以使用__weak修饰改为弱引用

  • 如果block中出现self时要加以注意,可能会出现循环引用(并非绝对)

  • 利用dealloc方法可以协助检测循环引用

调用

  • block_name(arg_list)

自定义视图传值:block与代理

实现

  • block

    • 调用方

      • 准备块代码
    • 被调用方

      • 定义代码块属性

      • 需要时执行

  • 代理

    • 代理

      • 遵守协议

      • 设置代理

      • 实现方法

    • 委托

      • 定义协议

      • 定义代理属性

      • 需要时调用代理方法

block与代理的选择

  • block与代理在一些场合时可以互换的

    • block

      • block适合比较小巧的回调,通常1~3回调方法比较合适

      • 如果回调的方法很多时使用block会显得很臃肿,例如UITableView

    • 代理

      • 使用代理可以制定协议方法是否必须实现

block数组排序/遍历

compare方法

  • 可以比较两个对象 (NSNumber, NSString, NSDate….)

compare

- (NSComparisonResult)compare:(NSNumber *)otherNumber;

数组排序

sortedArrayUsingComparator

- (NSArray *)sortedArrayUsingComparator:(NSComparator)cmptr NS_AVAILABLE(10_6, 4_0);
typedef NS_ENUM(NSInteger, NSComparisonResult) {NSOrderedAscending = -1L, NSOrderedSame, NSOrderedDescending};
/*
NSOrderedAscending = -1L, 升序
NSOrderedSame,            相同
NSOrderedDescending       降序
*/
#if NS_BLOCKS_AVAILABLE
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2);
#endif

数组遍历

  • 所有的参数都已经准备到位,可以直接使用

  • 效率比传统方式快(对比for ( in ){})

enumerate

- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

示例代码

array_block.m

#import <Foundation/Foundation.h>
int main(){
	NSArray* array = @[ @5, @4, @2, @1, @3 ];
	// 数组排序
   NSArray* result = [array sortedArrayUsingComparator:^NSComparisonResult(NSNumber* num1, NSNumber* num2) {
   	// 升序
   	return [num1 compare:num2];
    }];
   NSLog(@"%@", result);
}

// 数组遍历
void enumerate(NSArray *array){
    [array enumerateObjectsUsingBlock:^(NSNumber* num, NSUInteger idx, BOOL* stop) {
        NSLog(@"%@", num);
        if (idx == 3) { // 遍历到第三个时结束
            *stop = YES;
        }
    }];
}

block常见题目

block-copy

block_copy_release.m

#import <Foundation/Foundation.h>
typedef void^(myBlock)();
myBlock myDemo(){
	int i = 10;
	myBlock mb = ^{
		NSLog(@"i = %d",i);
	}
	//错误解决办法:⏎ [mb copy];
	return Block_copy(mb);
}
int main(){
	myBlock mb = myDemo();
	mb();
	Block_release(mb);
	return 0;
}

重构

  • 新建方法

  • 将代码复制到新方法

  • 调整参数

#import <Foundation/Foundation.h>
void myDay(void (^myWork)()) // 和 inlineBock 的左边一模一样
{
    NSLog(@"起床");
    NSLog(@"出门");
    // 执行block参数,在需要的时候执行
    myWork();
    NSLog(@"下班回家");
    NSLog(@"洗洗睡了");
}

void day1()
{
    // 准备代码,格式和inlineBlock右边一模一样
    myDay(^{
        NSLog(@"新人报道");
    });
}

void day2()
{
    myDay(^{
        NSLog(@"看公司代码");
    });
}

int main(){
	day1();
	day2();
	return 0;
}