复习时看的:

最大并发数 异步执行  同一个时间开启的线程数量

NSOperationQueue 需要掌握   默认都是 dispatch_get_global_queue()全局队列(并发的)     [NSOperationQueue mainQueue]主队列(同步 没有并发 不开新线程)

queue.maxConcurrentOperationCount = 3

dispatch_after  NSOperationQueue添加NSBlockOperation将operation变成block   相当于dispatch_async(queue,block)

【这个了解

NSBlockOperation  添加block  [op start]    第一个block不开新线程   第二个开始开新线程    setCompletion 相当于在最后一个block执行完毕后在里面追加一个方法

[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download:) object:nil] start];    //当前线程执行 所以价值不大

queue cancelAllOperations;  内存警告的时候调用一下  不可恢复

[queue setSuspended:YES]; //对性能要求很高的情况下 一般不用    发现用户滚动tableView暂时暂停下载操作

[queue setSuspended:NO];//恢复队列中的任务

-------------------

0916  线程 单例  操作

 

- (void)delay1
{
    // 延迟执行不要用sleep,坏处:卡住当前线程
    [NSThread sleepForTimeInterval:3];
    NSLog(@"-----下载图片-----");
}

 

- (void)delay2
{
    // 不会卡主当前线程
    [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
}

 

 

- (void)delay3
{
    // 3秒后回到主线程执行block中的代码 不卡当前线程
//    dispatch_queue_t queue = dispatch_get_main_queue();
//    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
//        NSLog(@"------task------%@", [NSThread currentThread]);
//    });
    
    // 开启新线程 执行block中的代码 不卡当前线程
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"------task------%@", [NSThread currentThread]);
    });
}

 

----

只要是 某个类的实例 只执行一次

【调用后  这个类对应的方法区 会将这个dispatch_once抹去 保证了无论多少个对象实例   都只有执行一次的机会  可以用于只允许下载一次的操作】

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"----touchesBegan");
    static dispatch_once_t onceToken; //自动生成的
    dispatch_once(&onceToken, ^{
        NSLog(@"----once");
        HMImageDownloader *downloader = [[HMImageDownloader alloc] init];
        [downloader download];
    });
}

 -----------

了解即可

队列组(2个队列放到一个组里  2个队列都执行完了 才执行dispatch_group_notify)(了解)

 同时下载2张图片  dispatch_group_notify回到主线程显示UI

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 1.队列组
    dispatch_group_t group = dispatch_group_create();
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    // 2.下载图片1
    __block UIImage *image1 = nil;
    dispatch_group_async(group, queue, ^{
        NSURL *url1 = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/image/pic/item/f2deb48f8c5494ee460de6182ff5e0fe99257e80.jpg"];
        NSData *data1 = [NSData dataWithContentsOfURL:url1];
        image1 = [UIImage imageWithData:data1];
    });
    
    // 3.下载图片2
    __block UIImage *image2 = nil;
    dispatch_group_async(group, queue, ^{
        NSURL *url2 = [NSURL URLWithString:@"http://su.bdimg.com/static/superplus/img/logo_white_ee663702.png"];
        NSData *data2 = [NSData dataWithContentsOfURL:url2];
        image2 = [UIImage imageWithData:data2];
    });
    
    // 4.合并图片 (保证执行完组里面的所有任务之后,再执行notify函数里面的block)
    dispatch_group_notify(group, queue, ^{
        // 开启一个位图上下文
        UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0);
        
        // 绘制第1张图片
        CGFloat image1W = image1.size.width;
        CGFloat image1H = image1.size.height;
        [image1 drawInRect:CGRectMake(0, 0, image1W, image1H)];
        
        // 绘制第2张图片
        CGFloat image2W = image2.size.width * 0.5;
        CGFloat image2H = image2.size.height * 0.5;
        CGFloat image2Y = image1H - image2H;
        [image2 drawInRect:CGRectMake(0, image2Y, image2W, image2H)];
        
        // 得到上下文中的图片
        UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();
        
        // 结束上下文
        UIGraphicsEndImageContext();
        
        // 5.回到主线程显示图片
        dispatch_async(dispatch_get_main_queue(), ^{
            self.imageView.image = fullImage;
        });
    });
}

--------

ARC变非ARC环境

1、

2、开启僵尸对象检测

 

 

 

 ----------

 --------------

单例模式

+(void)load类加载的时候调用

+(void)initialize 当类第一次干活时调用

+(void)load类加载的时候调用

+(void)initialize 当类第一次干活时调用

对象要实现 [obj copy] 需要实现 <NSCopint>协议 可以不用写<NSCoping> 因为这个只是方便敲出代码用的

如果定义全局变量 id _musicTool;
其他类里面也可以随意访问
extern id _musicTool;
应该 static id _musicTool 这样就只允许 MusicTool类对 _musicTool变量进行访问

懒汉式(推荐 面试经常问)

0916-线程 单例  操作    (单例)(NSOperationQueue)_单例模式0916-线程 单例  操作    (单例)(NSOperationQueue)_下载图片_02
//  HMMusicTool.m
//  03-单例模式-Singleton(掌握)
//  懒汉式

#import "HMMusicTool.h"

@implementation HMMusicTool
static id _instance;

/**
 *  alloc方法内部会调用这个方法
 */
+ (id)allocWithZone:(struct _NSZone *)zone
{
    if (_instance == nil) { // 防止频繁加锁
        @synchronized(self) {
            if (_instance == nil) { // 防止创建多次
                _instance = [super allocWithZone:zone];
            }
        }
    }
    return _instance;
}

+ (instancetype)sharedMusicTool
{
    if (_instance == nil) { // 防止频繁加锁
        @synchronized(self) {
            if (_instance == nil) { // 防止创建多次
                _instance = [[self alloc] init];
            }
        }
    }
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}
@end
View Code

 

饿汉式(了解即可 不需要掌握)

0916-线程 单例  操作    (单例)(NSOperationQueue)_单例模式0916-线程 单例  操作    (单例)(NSOperationQueue)_下载图片_02
//  HMSoundTool.m
//  03-单例模式-Singleton
//  饿汉式

#import "HMSoundTool.h"

@implementation HMSoundTool
static id _instance;

/**
 *  当类加载到OC运行时环境中(内存),就会调用一次(一个类只会加载1次)
 */
+ (void)load
{
    _instance = [[self alloc] init];
}

+ (id)allocWithZone:(struct _NSZone *)zone
{
    if (_instance == nil) { // 防止创建多次
        _instance = [super allocWithZone:zone];
    }
    return _instance;
}

+ (instancetype)sharedSoundTool
{
    return _instance;
}

- (id)copyWithZone:(NSZone *)zone
{
    return _instance;
}

///**
// *  当第一次使用这个类的时候才会调用
// */
//+ (void)initialize
//{
//    NSLog(@"HMSoundTool---initialize");
//}
@end
View Code

 

-

代理抽取成宏 放到pch文件中

 

----

 

----------------------

ARC 非ARC 代码适配

 -----------------

基于GCD(系统会根据cpu来决定开多少个  一般4~5个就不开了  同一时间  不要看num等于几)的NSOperation抽象类 常用

子类继承NSOperation实现内部方法

将操作放到  NSOperation抽像类的子类 对象中      子类对象放到NSOperationQuere中   系统自动取出NSQquere中的NSOeration子类对象a,并将a中的方法开启新线程执行

--------------

NSBlockOperation   由于

第一个任务用主线程     

第二个开始 都新增线程   

最后setCompletionBlock采用最后一个执行完毕的线程

a操作完成 后执行  异步

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1---%@",[NSThread currentThread]); //主线程
    }];

    [op setCompletionBlock:^{   // 新开的thread2 异步
        NSLog(@"3-----%@",[NSThread currentThread]);
    }];
   [op start];

 

 

    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1---%@",[NSThread currentThread]); //主线程
    }];
    [op addExecutionBlock:^{    //开启一个新线程 thread2 异步
        NSLog(@"2----%@",[NSThread currentThread]); 
    }];
    [op setCompletionBlock:^{   // 等待最后一个thread执行 完毕 采用最后一个线程来执行
        NSLog(@"3-----%@",[NSThread currentThread]);
    }];
    
    [op start];//第一个是主线程   第二个 第三个是 新开的线程

 

NSBlockOperation中任务大于等于2的时候会开启新线程    等于1的时候只开启一个当前线程 主线程

 --------------

最大并发数 异步执行  同一个时间开启的线程数量

NSOperationQueue 需要掌握   默认都是 dispatch_get_global_queue()全局队列(并发的)     [NSOperationQueue mainQueue]主队列(同步 没有并发 不开新线程)

maxConcurrentOperationCount = 3 很重要    最大新开多少个线程数   设置为1就是1个新线程串行   设置为3就是3个新线程并发  

 ------

使用NSOperationQueue是为了限制某个operation不能开新线程  operation里再加几个block也没用   这里operation变成一个Block了

如果在operation1 addExcutionBlock 也不会新增线程数量了

  最简单的异步执行方法   queue里添加几个就开几个新线程

这个比GCD更简单   是对GCD的封装

--------------

这个了解即可

[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download:) object:nil] start];    //当前线程执行 所以价值不大

 如果放到NSOperationQueue中,会自动开新线程 异步执行

 -----

依赖操作

 ------

C依赖A   C依赖B     就是 C操作在a后面   C操作在B后面

这样就实现了  等a下载图片  b下载图片都操作完了    再执行C合并图片操作

 -----

不同队列中的操作也可以依赖

 

 -----------

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        // 1.异步下载图片
        NSURL *url = [NSURL URLWithString:@"http://d.hiphotos.baidu.com/image/pic/item/37d3d539b6003af3290eaf5d362ac65c1038b652.jpg"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        // 2.回到主线程,显示图片
//        [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
//        dispatch_async(dispatch_get_main_queue(), ^{
//            
//        });
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];
}

 

 ---------------

queue cancelAllOperations;  内存警告的时候调用一下  不可恢复

[queue setSuspended:YES]; //对性能要求很高的情况下 一般不用    发现用户滚动tableView暂时暂停下载操作

[queue setSuspended:NO];//恢复队列中的任务

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    
//    [queue cancelAllOperations]; // 取消队列中的所有任务(不可恢复)
}
-(void)didReceiveMemoryWarning1
{
    [super didReceiveMemoryWarning];
//    [queue cancelAllOperations];
}

- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
//    [queue setSuspended:YES]; // 暂停队列中的所有任务
//    [queue setSuspended:YES];//暂停
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
//    [queue setSuspended:NO]; // 恢复队列中的所有任务
//    [queue setSuspended:NO];
}

 

----------------------------------

其他:

 

单例(宏的方式)代码找到放到微云里