block

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了block相关的知识,希望对你有一定的参考价值。

block是匿名函数
block的类型:void (^)()
^只是用来表示这是一个block对象,和函数指针中的*的作用一样,只是一个标识符

block正常储存在栈区和全局区 用copy就会储存在堆区
注意在MRC下使用copy,在ARC下使用,也可以使用strong用来修饰,在strong中碰到block会自动有copy到堆内存的功能,但是苹果官方还是推荐使用copy

MARK: 这里值得一提的是大部分的时候NSString的属性都是copy,那修饰NSString时候copy与strong的情况下到底有什么区别呢?

这是因为

对源头是NSMutableString的字符串,retain仅仅是指针引用,增加了引用计数器,这样源头改变的时候,用这种retain方式声明的变量(无论被赋值的变量是可变的还是不可变的),它也会跟着改变;而copy声明的变量,它不会跟着源头改变,它实际上是深拷贝。

对源头是NSString的字符串,无论是retain声明的变量还是copy声明的变量,当第二次源头的字符串重新指向其它的地方的时候,它还是指向原来的最初的那个位置,也就是说其实二者都是指针引用,也就是浅拷贝。

另外说明一下,这两者对内存计数的影响都是一样的,都会增加内存引用计数,都需要在最后的时候做处理。

其 实说白 了,对字符串为啥要用这两种方式?我觉得还是一个安全问题,比如声明的一个NSString *str变量,然后把一个NSMutableString *mStr变量的赋值给它了,如果要求str跟着mStr变化,那么就用retain;如果str不能跟着mStr一起变化,那就用copy。而对于要把 NSString类型的字符串赋值给str,那两都没啥区别。不会影响安全性,内存管理也一样。

详见链接:http://blog.csdn.net/itianyi/article/details/9018567

首先来一个简单的block的问题

技术分享
        int a = 10;
        void (^myBlock)() =
        ^{
            NSLog(@"a = %d",a);
            
        };
        myBlock();
技术分享

第一问:在block块内部能否访问到外部变量    答案是:可以

技术分享
        int a = 10;
        void (^myBlock)() =
        ^{
            NSLog(@"a = %d",a);
            
        };
        myBlock();
技术分享

第二问:在block块内部能否改变外部变量的值    答案:不可以,局部变量存放在栈区,block存放在堆区 ,调用的时候根本找不到

技术分享
        int a = 10;  // 局部变量存放在栈区
        void (^myBlock)() =   // 存放在堆区
        ^{
            a = 100;   // 以const的方式进行值拷贝
            NSLog(@"a = %d",a);
            
        };
        myBlock();
技术分享

第三问:block内部访问a和外部变量a的地址是否一样   答案:答:不一样,外部存放在栈区,内部a存放在堆区

技术分享
int a = 10;
        NSLog(@"外部 a = %p", &a);  // 栈区地址
        void (^myBlock)() =
        ^{
            NSLog(@"内部 a = %p", &a);  // 堆区地址
        };
        myBlock();
技术分享

打印结果

2016-06-02 15:14:26.828 OCLesson7Test[21467:387054] 外部 a = 0x7fff5fbff7dc
2016-06-02 15:14:26.829 OCLesson7Test[21467:387054] 内部 a = 0x1003000e0
Program ended with exit code: 0

第四问:如果我想在block内部改变外部的值该怎么办?    答案:答:方法1:把外部的变量定义为全局变量  方法2: 如果是局部变量,在局部变量定义前使用__block修饰

技术分享
        static int a = 10;
        // 或者
        // __block int a = 10;

        void (^myBlock)() =
        ^{
            a = 100;
            NSLog(@"%d", a);
        };
        myBlock();
        NSLog(@"%d", a);
技术分享

第五问:此时a的值是多少?     答案:修改后的值

设置两个controller,点击第一个controller的右按钮push到第二个controller,在第二个controller中声明无参无返block属性,实现改变view的颜色;

实现block
    

在controller中定一block属性
实现block的时候,如果block里面需要使用当前控制器对象,不可以直接使用self否则
会引起循环引用

使用__weak修饰防止循环引用
__block是在MRC中使用的

技术分享
 __weak typeof (self) secondVC = self;
    
    self.block = ^void() {
        NSLog(@"这是block的实现");
        secondVC.view.backgroundColor = [UIColor colorWithRed:arc4random() % 256 / 256.0 green:arc4random() % 256 / 256.0 blue:arc4random() % 256 / 256.0 alpha:1];
    };
    // 调用
    self.block();
技术分享

控制器销毁会走这个方法

- (void)dealloc {
//    [super dealloc];  mrc必须写,ARC不写
    NSLog(@"第二个控制器被销毁");
    
}

以上是关于block的主要内容,如果未能解决你的问题,请参考以下文章

Sphinx - 在代码块片段中使用省略号 (...)

Objective-C Block与函数指针比较

使用do block vs braces {}

为啥 GL_MAX_UNIFORM_BLOCK_SIZE 的值会发生变化?

控件集合无法修改,因为控件包含代码块(即 <% ... %>)

20160215.CCPP体系详解(0025天)