A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 小小小笑 初级黑马   /  2015-4-18 12:53  /  1147 人查看  /  2 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 余攀 于 2015-4-18 13:38 编辑

一、使用block的好处:
(1)可以改变代码从上到下的执行的顺序 》 使用block
(2)让代码集中在一处,避免了代理那样需要在不同代码中来回跳转,便于代码维护/阅读


二、block的用途
1、block是用来封装一段代码,在需要的时候执行
2、block是一种数据类型,可以当做参数传递(使用多),也可以当做返回值(用的少)


三、block的用法理解
0、返回值类型 + (^名字)+(参数列表) ===  block
1、预先封装好一段代码,合适的时候再次调用block就会执行这段代码


2、是一种数据类型,可以用来指定变量类型
- (void)downloadImage:(NSString *)urlString completion:(void (^) (UIImage *image))completion;
3、可以作为方法的参数使用
(1)简单的传参,在同一个控制器中:
void myWork(void (^dayWork)()) {
    // 是一个预先准备好的代码,在需要的时候执行!
    dayWork();

}


void dailyWork(int day) {
     void (^work)() =  ^{
                NSLog(@"入职报道");
            };
   // block可以当作参数传递

    myWork(work);
}
//调用


void dailyWork(1) ;


(2)复杂传参,在多个控制器之间
***WebImageManager.m文件中:
实现WebImageOperation类的的声明de方法,封装了一段代码到completion,block中,作为参数传递到WebImageOperation.m文件中使用。


[webImageOperationWithURLString:urlString completion:^(UIImage *image) {


        // 下载操作完成后,从缓冲池中删除下载操作
        [self.operationCacheremoveObjectForKey:urlString];


        // 将图像添加到图像缓冲池
        [self.imageCache setObject:image forKey:urlString];      
        // 执行调用方传递的回调
        if (completion != nil) {
            completion(image);
        }

    }];


***WebImageOperation.h文件中,声明+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage*image))completion;这个方法
***WebImageOperation.m文件中:
(1)定义了一个block类型的属性:@property(nonatomic, copy) void (^completion) (UIImage*image);
(2)调用这个方法:+ (instancetype)webImageOperationWithURLString:(NSString *)urlString completion:(void (^)(UIImage*))completion {


    WebImageOperation *op = [[self alloc] init];


    op.urlString = urlString;


    // block 完全就是一个参数
    op.completion = completion;
    return op;

}

此时,completion这个block作为参数,从另一个控制器传过来了,并赋值给当前控制器的completion属性,以便后面使用。



4、可以作为返回值使用







四、block的三种定义方式
(0)使用提示快速输入:
inlineblock,能够快速敲出一个block的基本结构


(1)无参数,无返回值:   
void (^myBlock)() = ^ {
        NSLog(@"hello");
    };
(2)有参数,无返回值
   // 定义带参数的block
    // 格式:void (^block名称)(参数列表) = ^ (参数列表) { // 代码实现; }
    void (^sumBlock)(int, int) = ^ (int x, int y) {

        NSLog(@"%d", x + y);
    };
(3)有参数,有返回值
    // 定义带返回值的block
    // 格式:返回类型 (^block名称)(参数列表) = ^ 返回类型 (参数列表) { // 代码实现; }
    int (^sumBlock2)(int, int) = ^ int (int a, int b) {
        return a + b;

    };
五、block修改外部变量的总结:


六、关于block,循环引用的理解

(0)循环引用:比如控制器self强引用着block,block里面又有某个对象强引用着self
(1)block中使用到外面的对象或者self,要使用__weak来修饰

(2)因为block不确定什么时候调用,所以会强引用着需要用到的对象,防止到时候调用block的时候这个对象已经被释放了
在创建block的时候,控制器会默认对block进行强引用。


(3)所以如果可以保证block使用的对象在block调用时一定还存在,没有被释放,就不需要使用强引用,改成__weak;

(4)【疑问】— 什么情况下不能使用__weak修饰,一定要用强引用 (默认情况下就是强引用)


五、关于定义block时,为什么要使用copy,而不使用weak、strong?
(1)首先排除weak,因为block是一个数据类型,作用类似于方法,可以封装一段代码,如果使用weak,一创建出来就被销毁了
(2)strong:strong是强指针,会对修饰的对象retain一次;block是定义在函数内部的,是局部变量,所以block对象是保存在栈区的,栈区的对象在作用域过掉之后,就应该被释放掉的,但是如果使用strong修饰的话,会导致作用域过掉,栈区的block还是不能释放,这是不对的。
(3)copy:copy修饰的对象会把该对象的地址以及内容从栈区通通拷贝一份,放到堆区,那么当block所在的作用域过掉,block从栈区被释放,但是在堆区还有保留,所以这样既可以满足block不被过早释放,也不会破坏栈区对象生命周期的管理原则。至于堆区的block什么时候释放,在ARC环境下不需要程序员考虑。



评分

参与人数 3黑马币 +70 收起 理由
仰望的繁华 + 10 让那些水贴的看看,认真发帖得到的更多。.
余攀 + 40 很给力,学习了,以后多分享
shicuf + 20 内容很不错,如果是自己总结的可以算比较全.

查看全部评分

2 个回复

倒序浏览
不错,又学习了
回复 使用道具 举报
楼主可以直接兑换10技术分去申请流程了。
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马