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(@"第二个控制器被销毁"); }