iOS面试总结Objective-C

IOS多线程的方式

2019-05-09  本文已影响3人  越天高

pthread的基本使用(需要包含头文件)

需要#import <pthread.h>

  //使用pthread创建线程对象
    pthread_t thread;
    NSString *name = @"wendingding";
    //使用pthread创建线程
    //第一个参数:线程对象地址
    //第二个参数:线程属性
    //第三个参数:指向函数的指针
    //第四个参数:传递给该函数的参数
    pthread_create(&thread, NULL, run, (__bridge void *)(name));

3 NSThread

//特点:需要手动开启线程,可以拿到线程对象进行详细设置
    //创建线程
    /*
     第一个参数:目标对象
     第二个参数:选择器,线程启动要调用哪个方法
     第三个参数:前面方法要接收的参数(最多只能接收一个参数,没有则传nil)
     */
    NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"wendingding"];
     //启动线程
    [thread start];
//特点:自动启动线程,无法对线程进行更详细的设置
    /*
     第一个参数:线程启动调用的方法
     第二个参数:目标对象
     第三个参数:传递给调用方法的参数
     */
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"我是分离出来的子线程"];
//特点:自动启动县城,无法进行更详细设置
[self performSelectorInBackground:@selector(run:) withObject:@"我是后台线程"];

设置线程的属性

//设置线程的名称
thread.name = @"线程A";

//设置线程的优先级,注意线程优先级的取值范围为0.0~1.0之间,1.0表示线程的优先级最高,如果不设置该值,那么理想状态下默认为0.5
thread.threadPriority = 1.0;

线程的各种状态:新建-就绪-运行-阻塞-死亡

//常用的控制线程状态的方法
[NSThread exit];//退出当前线程
[NSThread sleepForTimeInterval:2.0];//阻塞线程
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];//阻塞线程
//注意:线程死了不能复生

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    NSThread *threadA = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"AA"];
    [threadA start];
}


- (void)run:(NSString *)name
{
    NSLog(@"--%@", name);
    [NSThread sleepForTimeInterval:2.0];
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];

    NSLog(@"----%@", name);

    
}

- (void)task:(NSString *)name
{
    NSLog(@"%@", name);
    for (NSInteger i = 0; i<100 ;i++) {
        NSLog(@"%zd---%@",i,[NSThread currentThread]);
        
        if (i == 20) {
             //[NSThread exit];  //退出当前线程
            break;              //表示任务已经执行完毕.
        }
    }

}

线程安全

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    
    //设置中票数
    self.totalCount = 100;
    
     self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
     self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
     self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
    
    self.threadA.name = @"售票员A";
    self.threadB.name = @"售票员B";
    self.threadC.name = @"售票员C";
    
    //启动线程
    @synchronized(self) {
        [self.threadA start];
        [self.threadB start];
        [self.threadC start];
    }
    
}

-(void)saleTicket
{
    while (1) {
        
    //锁:必须是全局唯一的
    //1.注意枷锁的位置
    //2.注意枷锁的前提条件,多线程共享同一块资源
    //3.注意加锁是需要代价的,需要耗费性能的
    //4.加锁的结果:线程同步
        
    @synchronized(self) {
        //线程1
        //线程2
        //线程3
        NSInteger count = self.totalCount;
        if (count >0) {
            
            for (NSInteger i = 0; i<1000000; i++) {
            }
            
            self.totalCount = count - 1;
            //卖出去一张票
            NSLog(@"%@卖出去了一张票,还剩下%zd张票", [NSThread currentThread].name,self.totalCount);
        }else
        {
            NSLog(@"不要回公司上班了");
            break;
        }
        }
    }
    
}

线程之间的通信

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
   [ NSThread detachNewThreadSelector:@selector(downLoadImage) toTarget:self withObject:nil];
}

- (void)downLoadImage
{
    NSURL *url = [NSURL URLWithString:@"http://e.hiphotos.baidu.com/image/h%3D300/sign=a9e671b9a551f3dedcb2bf64a4eff0ec/4610b912c8fcc3cef70d70409845d688d53f20f7.jpg"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    NSLog(@"当前线程%@", [NSThread currentThread]);
    //返回主线程刷新页面
    //4.回到主线程显示UI
    /*
     第一个参数:回到主线程要调用哪个方法
     第二个参数:前面方法需要传递的参数 此处就是image
     第三个参数:是否等待
     */
    //[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
    
    //    [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
    
    [self.downloadImageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
}

GCD

//1.创建队列
    /*
     第一个参数:C语言的字符串,标签
     第二个参数:队列的类型
     DISPATCH_QUEUE_CONCURRENT:并发
     DISPATCH_QUEUE_SERIAL:串行
     */
    //dispatch_queue_t queue = dispatch_queue_create("com.520it.download", DISPATCH_QUEUE_CONCURRENT);
    
    //获得全局并发队列
    /*
     第一个参数:优先级
     第二个参数:
     */
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    NSLog(@"---start--");
    //2.1>封装任务2>添加任务到队列中
    /*
     第一个参数:队列
     第二个参数:要执行的任务
     */
    
    dispatch_async(queue, ^{
        
        NSLog(@"download1----%@",[NSThread currentThread]);
        
        for (int i = 0; i < 10000; i++) {
            NSLog(@"AA%i",i );
        }
    });
    dispatch_async(queue, ^{
        NSLog(@"download2----%@",[NSThread currentThread]);
        for (int i = 0; i < 10000; i++) {
            NSLog(@"BB%i",i );

        }
    });
    
    dispatch_async(queue, ^{
        NSLog(@"download3----%@",[NSThread currentThread]);
        for (int i = 0; i < 10000; i++) {
            NSLog(@"CC%i",i );
        }
    });
    
    NSLog(@"---end----");

02 异步函数+串行队列:开启一条线程,串行执行任务

dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
          NSLog(@"download1-------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"AAA%i",i );
            
        }
    });
    dispatch_async(queue, ^{
         NSLog(@"download1--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"BB%i",i );
            
        }
    });dispatch_async(queue, ^{
        
          NSLog(@"download1--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"CCC%i",i );
            
        }
    });

03 同步函数+并发队列:不开线程,串行执行任务

dispatch_queue_t queue = dispatch_queue_create("520.download.com", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        
        NSLog(@"download1--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"AAA%i",i );
            
        }
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"download2--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"BBB%i",i );
            
        }
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"download3--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"CCC%i",i );
            
        }
    });

04 同步函数+串行队列:不开线程,串行执行任务

dispatch_queue_t queue = dispatch_queue_create("download.520.com", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        
        NSLog(@"download1--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"AAA%i",i );
            
        }
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"download2--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"BBB%i",i );
            
        }
    });
    
    dispatch_sync(queue, ^{
        
        NSLog(@"download3--------%@",[NSThread currentThread]);
        for (int i = 0; i < 1000; i++) {
            NSLog(@"CCC%i",i );
            
        }
    });
    

05 异步函数+主队列:不开线程,在主线程中串行执行任务

 dispatch_queue_t queue = dispatch_get_main_queue();
    NSLog(@"start");

    dispatch_async(queue, ^{
        NSLog(@"downLoad ---%@", [NSThread currentThread]);
        for (int i = 0; i< 100; i++) {
            NSLog(@"AA%i",i);
        }
    });
    
    dispatch_async(queue, ^{
        NSLog(@"downLoad ---%@", [NSThread currentThread]);
        for (int i = 0; i< 100; i++) {
            NSLog(@"BB%i",i);
        }
    });
    
    dispatch_async(queue, ^{
        NSLog(@"downLoad ---%@", [NSThread currentThread]);
        for (int i = 0; i< 100; i++) {
            NSLog(@"CC%i",i);
        }
    });
    NSLog(@"end");

06 同步函数+主队列:不开线程,串行执行任务(注意死锁发生)
同步函数+主队列:死锁

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"downloadAA --%@",[NSThread currentThread]);
    });

07 注意同步函数和异步函数在执行顺序上面的差异

GCD之间的通信

 //0.获取一个全局的队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

    //1.先开启一个线程,把下载图片的操作放在子线程中处理
    dispatch_async(queue, ^{

       //2.下载图片
        NSURL *url = [NSURL URLWithString:@"http://h.hiphotos.baidu.com/zhidao/pic/item/6a63f6246b600c3320b14bb3184c510fd8f9a185.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];

        NSLog(@"下载操作所在的线程--%@",[NSThread currentThread]);

        //3.回到主线程刷新UI
        dispatch_async(dispatch_get_main_queue(), ^{
           self.imageView.image = image;
           //打印查看当前线程
            NSLog(@"刷新UI---%@",[NSThread currentThread]);
        });

    });

GCD常用函数

//1. 延迟执行的第一种方法
    //[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
    
    //2.延迟执行的第二种方法
    //[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(task) userInfo:nil repeats:YES];
    //3GCD
    /*
    第一个参数:DISPATCH_TIME_NOW 从现在开始计算时间
    第二个参数:延迟的时间 2.0 GCD时间单位:纳秒
    第三个参数:队列*/
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),queue , ^{
        [self task];
    });
- (void)once
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"once only");
    });
}

栅栏函数

栅栏函数不能使用全局并发队列
    //dispatch_queue_t queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //0.获得并发队列

    dispatch_queue_t queue = dispatch_queue_create("download", DISPATCH_QUEUE_CONCURRENT);
    
    //1.异步函数
    dispatch_async(queue, ^{
        
        for (NSInteger i = 0; i<100; i++) {
            NSLog(@"download1-%zd-%@",i,[NSThread currentThread]);
        }
        
    });
    
    dispatch_async(queue, ^{
        
        for (NSInteger i = 0; i<100; i++) {
            NSLog(@"download2-%zd-%@",i,[NSThread currentThread]);
        }
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"++++++++++++++++++++++++");
    });
   
    dispatch_async(queue, ^{
        
        for (NSInteger i = 0; i<100; i++) {
            NSLog(@"download3-%zd-%@",i,[NSThread currentThread]);
        }
        
    });
    
    dispatch_async(queue, ^{
        
        for (NSInteger i = 0; i<100; i++) {
            NSLog(@"download4-%zd-%@",i,[NSThread currentThread]);
        }
    });
    ```

#队列组

06进入群组和离开群组
    dispatch_group_enter(group);//执行该函数后,后面异步执行的block会被gruop监听
    dispatch_group_leave(group);//异步block中,所有的任务都执行完毕,最后离开群组

/*
1.下载图片1 开子线程
2.下载图片2 开子线程
3.合成图片并显示图片 开子线程
*/

//-1.获得队列组
dispatch_group_t group = dispatch_group_create();

//0.获得并发队列
dispatch_queue_t queue =  dispatch_get_global_queue(0, 0);

// 1.下载图片1 开子线程
dispatch_group_async(group, queue,^{
    
    NSLog(@"download1---%@",[NSThread currentThread]);
    //1.1 确定url
    NSURL *url = [NSURL URLWithString:@"http://www.qbaobei.com/tuku/images/13.jpg"];
    
    //1.2 下载二进制数据
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    
    //1.3 转换图片
    self.image1 = [UIImage imageWithData:imageData];
});

// 2.下载图片2 开子线程
 dispatch_group_async(group, queue,^{
     
     NSLog(@"download2---%@",[NSThread currentThread]);
     //2.1 确定url
    NSURL *url = [NSURL URLWithString:@"http://pic1a.nipic.com/2008-09-19/2008919134941443_2.jpg"];
    
    //2.2 下载二进制数据
    NSData *imageData = [NSData dataWithContentsOfURL:url];
    
    //2.3 转换图片
    self.image2 = [UIImage imageWithData:imageData];
});

//3.合并图片
//主线程中执行
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
   
    NSLog(@"combie---%@",[NSThread currentThread]);
    //3.1 创建图形上下文
    UIGraphicsBeginImageContext(CGSizeMake(200, 200));
    
    //3.2 画图1
    [self.image1 drawInRect:CGRectMake(0, 0, 300, 300)];
    self.image1 = nil;
    
    //3.3 画图2
    [self.image2 drawInRect:CGRectMake(100, 100, 20, 10)];
    self.image2 = nil;
    
    //3.4 根据上下文得到一张图片
    UIImage *image =  UIGraphicsGetImageFromCurrentImageContext();
    
    //3.5 关闭上下文
    UIGraphicsEndImageContext();
    
    //3.6 更新UI

// dispatch_async(dispatch_get_main_queue(), ^{

        NSLog(@"UI----%@",[NSThread currentThread]);
        self.imageView.image = image;

// });
});

上一篇 下一篇

猜你喜欢

热点阅读