多线程(二)之block小结

http://www.cnblogs.com/lingzhiguiji/p/3701666.html

根据上述的博客小结如下:

Block的类型与内存管理
根据Block在内存中的位置分为三种类型NSGlobalBlock,NSStackBlock, NSMallocBlock。
        NSGlobalBlock:类似函数,位于text段;
        NSStackBlock:位于栈内存,函数返回后Block将无效;
        NSMallocBlock:位于堆内存。

无论MRC还是ARC,只要在block内部没有访问局部变量,那么这个block就存放在静态区(全局区,或者说是数据区)即NSGlobalBlock区

MRC模式下:block内部访问局部变量,这个block是存放到栈区的

ARC模式下:block内部访问局部变量,这个block是存放到堆区的

无论MRC还是ARC,局部变量copy后,这个block是存放到堆区的即NSMallocBlock

//MRC copy 使得栈区的block 拷贝到堆区,在旧版本的xcode中,strong不会拷贝到堆取,在新版本的xcode中,不管strong还是copy都在堆取,意图是让程序员少考虑内存问题,专注于业务逻辑

-(void)demo4{
    //block 内修改外部变量,__block,把变量移到堆取
   __block int number = 10;
   NSLog(@"11 %p",&number);

    //拷贝到堆取,因为生命周期比较长,不会被立即释放
    void(^myBlock)() = ^{

        number = 20;
        NSLog(@"22 %p",&number);
        NSLog(@"%d",number);

    };

    NSLog(@"33 %p",&number);
    NSLog(@"%d---",number);

    [self passBlock:myBlock];
}

但对于像:

NSMutableString *str = [NSMutableString string];

NSMutableArray *arr = [NSMutableArray array];

NSMutableDictionary *dic = [NSMutableDictionary dictionary];

这三类定义的局部变量我不用在前面加__block,也能在block内部改变变量的值,因为,举例:str来说,str是存放在栈区的局部变量,但是实例化的对象却是在堆区中,所以我给这个对象改变值是可以直接改变的,但像上述例子中的int对象,显然是只存在栈区的,而我在block中是相当于copy了一份在堆区,那么,显然堆区中再去访问栈区以达到改变栈区值的目的是不可行的.

另外:__weak的目的就是为了避免循环引用,为什么会产生循环引用呢?因为

-(void)demo1{
    //定义block,内部引用self
    //方法中self->block->self
    //方法执行完 block->self
    //并不是所有在block内部使用self就会造成循环引用的问题(retain cycle)

    void(^myBlock)() = ^{
        NSLog(@"%d,%@",self.number,self);
    };

    myBlock();
    self.myblock2 = myBlock;
}

-(void)dealloc{
    //套路:检查有没有循环引用,就查看dealloc是否被调用//ps:循环引用不会调用这个方法,因为一直在互相引用,控制器没有被释放,没有循环引用才会调用这个方法,控制器再pop后会被释放掉.
    NSLog(@"%s",__FUNCTION__);
}

这个代码中注意:myBlock 中打印了self说明,myBlock引用了控制器对象self,self.myblock2 = myBlock;这行代码又用myBlock给控制器的属性赋值说明,控制器对myBlock也进行了引用,所以互相引用就造成了循环引用,因此解决循环引用就如下代码所示(加__weak):

-(void)demo2{

    //写法1 self->myBlock->weakVC
    __weak ViewController *weakVC = self;
    //写法2
    __weak typeof(self) weakSelf = self;
    void(^myBlock)() = ^{
        NSLog(@"%d",weakSelf.number);
    };

    self.myblock2 = myBlock;

}
//
//  ViewController.m
//  blockDemo
//
//  Created by apple on 16/8/20.
//  Copyright ? 2016年 itcast. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

//MRC copy 使得栈区的block 拷贝到堆区,在旧版本的xcode中,strong不会拷贝到堆取,在新版本的xcode中,不管strong还是copy都在堆取,意图是让程序员少考虑内存问题,专注于业务逻辑
@property(nonatomic,strong) void(^myblock2)();

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    [self demo1];
}

-(void)demo7{
//MRC栈区的block 拷贝到堆区
    int number = 10;
    void(^myBlock)() = ^{
        NSLog(@"block %d",number);
    };

    self.myblock2 = myBlock;
     NSLog(@"%@",self.myblock2);

}

-(void)demo6{
    /**
     ARC 会自动的把block拷贝到堆取
     *  __NSMallocBlock__堆区block
     MRC
     __NSStackBlock__ 栈去block
     */
    int number = 10;
    void(^myBlock)() = ^{
        NSLog(@"block %d",number);
    };

     NSLog(@"%@",myBlock);
}

-(void)demo5{
//block在内存中的位置
    //__NSGlobalBlock__
    void(^myBlock)() = ^{
        NSLog(@"block");
    };

    NSLog(@"%@",myBlock);
}

-(void)demo4{
    //block 内修改外部变量,__block,把变量移到堆取
   __block int number = 10;
   NSLog(@"11 %p",&number);

    //拷贝到堆取,因为生命周期比较长,不会被立即释放
    void(^myBlock)() = ^{

        number = 20;
        NSLog(@"22 %p",&number);
        NSLog(@"%d",number);

    };

    NSLog(@"33 %p",&number);
    NSLog(@"%d---",number);

    [self passBlock:myBlock];
}

-(void)demo3{
    //面试题:打印输出是? 10 block在声明的时候,拷贝了block内部涉及的变量,内存地址不唯一
    int number = 10;
    NSLog(@"11 %p",&number);

    void(^myBlock)() = ^{
        NSLog(@"%d",number);
         NSLog(@"2 %p",&number);
//        number = 20;
//        NSLog(@"block %p   ",myBlock);

    };

    number = 20;

    [self passBlock:myBlock];

}

-(void)demo2{
//使用block在方法间传递参数
    void(^myBlock)() = ^{
        NSLog(@"block");
    };

    [self passBlock:myBlock];
}

-(void)passBlock:(void(^)())block{
//调用传递过来的block
    block();
}

- (void)demo1 {
    //返回值 名字 参数 与函数或者方法很像
    void(^myBlock)() = ^{
        NSLog(@"block");
    };

    NSLog(@"%@",myBlock);
    //调用block
    myBlock();
}

@end
时间: 2024-10-14 15:29:53

多线程(二)之block小结的相关文章

pthread多线程编程的学习小结

pthread多线程编程的学习小结 程序员必上的开发者服务平台 —— DevStore pthread多线程编程整理 1 Introduction 不用介绍了吧… 2 Thread Concepts 1.     Thread由下面部分组成: a.     Thread ID b.     Stack c.     Policy d.     Signal mask e.     Errno f.      Thread-Specific Data 3 Thread Identification

多线程二(GCD)代码笔记

// // TWFXViewController.h // Demo_GCD // // Created by Lion User on 12-12-11. // Copyright (c) 2012年 Lion User. All rights reserved. // #import <UIKit/UIKit.h> @interface TWFXViewController : UIViewController @property (retain, nonatomic) IBOutlet

iOS开发系列之二 - UILabel 用法小结

// 初始化标签 UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 100, 300, 150)]; // 设置标签文字 label.text = @"This is a test text.This is a test text.This is a test text."; // 设置标签文字字体 // 使用系统字体 label.font = [UIFont systemFontOfSize:20]; //

Cocoa多线程编程之block与semaphore(信号量)

首先大家要了解 dispatch_queue 的运作机制及线程同步 我们可以将许多 blocks 用 dispatch_async 函数提交到 dispatch_queue ,如果类型是DISPATCH_QUEUE_SERIAL (串行),那么这些 block 是按照 FIFO (先入先出)的规则调度的,也就是说,先加入的先执行,后加入的一定后执行,但在如果类型是DISPATCH_QUEUE_CONCURRENT(并行),那么某一时刻就可能有多个 block 同时在执行. 这个时候,如果两个 b

python多线程(二)

原文:http://blog.sina.com.cn/s/blog_4b5039210100esc1.html 基础不必多讲,还是直接进入python. Python代码代码的执行由python虚拟机(也叫解释器主循环)来控制.Python在设计之初就考虑到要在主循环中,同时只有一个线程在执行,就像单CPU的系统中运行多个进程那样,内存中可以存放多个程序,但任意时候,只有一个程序在CPU中运行.同样,虽然python解释器可以“运行”多个线程,但在任意时刻,只有一个线程在解释器中运行. 对pyt

JavaScript学习笔记(二)——选项卡小结

Js制作选项卡小结 1.先构思好需要展示的页面效果,比如这样 2.需要显示的效果通过html和css制作出来,包括选项(第一课.第二课)的鼠标停留背景变色.下方选项页内容切换的内容等. 3.把此选项卡分为上下两个部分,并且3个选项对应3个选项页面.上方为id为tab的固定div,需要变换的是鼠标放入li时li切换背景(比如此时li为灰色背景):下方为content容器div,放入需要展示的内容(本例中为3个ul),初始效果为第一个ul显示block,后面两个为display:none. 4.将需

【黑马】程序员————多线程(二)单例设计模式、线程间通信,JDK1.5互斥锁

------Java培训.Android培训.iOS培训..Net培训.期待与您交流!----- 一.单例设计模式 单例设计模式的意义: A.保证类在内存中只有一个对象,不提供外部访问方式,构造函数用private修饰. B.提供公共方法(static修饰,类的静态方法),获取类的实例.单例设计模式分为饿汉和懒汉两种模式. 饿汉式&懒汉式 class Test33 { public static void main(String[] args) { Fanjianan.getInstance()

Java:多线程&lt;二&gt; 同步

由于多线程的访问出现延迟和线程的随机性,在使用多线程时往往会伴随安全性的问题,这些问题一旦出现将会是非常严重的.为了解决这种安全性问题,synchronized出现了. synchronized用法一,放在方法内,必须传一个对象obj synchronized(obj) { //需要被同步的代码 } synchronized用法二,放在方法上,不需要传对象 public synchronized void method() { //该方法体中所有的代码都被同步了 } 例子:银行有个小金库,初始为

黑马程序员——java基础---多线程(二)

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! -------  线程间的通信:简单来说,就是多个线程在操作同一资源,但操作的动作不同. 试想一下,对于同一个资源做不同的操作,这势必会在操作的过程中产生矛盾.为了避免这种情况的发生,就需要用的synchronized来保证,每次对共享资源的操作,只能是一条线程在进行.在用到同步的时候,就会因需求问题用到wait().notify().notifyAll()这三个方法. wait()方法:作用是使调用线程自动