15 - GCD搞乏、NSOperation

  • 全稱是Grand Central Dispatch波桩,可譯為“牛逼的中樞調(diào)度器”
  • 純C語言,提供了非常多強(qiáng)大的函數(shù)

GCD的優(yōu)勢 :

  1. GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
  2. GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核查描、四核)
  3. GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程突委、調(diào)度任務(wù)瘩将、銷毀線程)
  4. 程序員只需要告訴GCD想要執(zhí)行什么任務(wù)畅厢,不需要編寫任何線程管理代碼

GCD的使用就兩個(gè)步驟 :

  1. 定制任務(wù)(確定想做的事情)
  2. 將任務(wù)添加到隊(duì)列中GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出志鹃,放到對應(yīng)的線程中執(zhí)行,任務(wù)的取出遵循隊(duì)列的FIFO(First in First out)原則:先進(jìn)先出恭应,后進(jìn)后出

GCD有兩個(gè)核心概念 :

概念一 : 任務(wù) (執(zhí)行什么操作)

GCD中有兩個(gè)用來執(zhí)行任務(wù)的函數(shù)

// 用同步的方式執(zhí)行任務(wù) :只能在當(dāng)前線程中執(zhí)行任務(wù)聋丝,不具備開啟新線程的能力

//  sync: 同步                 queue:隊(duì)列           block:任務(wù)    
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

// 用異步的方式執(zhí)行任務(wù) : 可以在新的線程中執(zhí)行任務(wù)芳肌,具備開啟新線程的能力

//  async: 異步                 queue:隊(duì)列           block:任務(wù)   
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

概念二 : 隊(duì)列 :(用來存放任務(wù))

GCD中的隊(duì)列可以分為兩大類型
1: 并發(fā)隊(duì)列(Concurrent Dispatch Queue):
  • 可以讓多個(gè)任務(wù)并發(fā)同時(shí)執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
  • 并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效
2: 串行隊(duì)列(Serial Dispatch Queue)
  • 讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后接谨,再執(zhí)行下一個(gè)任務(wù))

同步笼蛛、異步窝爪、并發(fā)弛车、串行的作用:

  • 同步和異步主要影響:能不能開啟新的線程
  • 同步:在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
  • 異步:在新的線程中執(zhí)行任務(wù)蒲每,具備開啟新線程的能力
  • 并發(fā)和串行主要影響:任務(wù)的執(zhí)行方式
  • 并發(fā):多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行
  • 串行:一個(gè)任務(wù)執(zhí)行完畢后纷跛,再執(zhí)行下一個(gè)任務(wù)

并發(fā)隊(duì)列與串行隊(duì)列

并發(fā)隊(duì)列

GCD的默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列,供整個(gè)應(yīng)用使用,不需要手動(dòng)創(chuàng)建.

  1. 獲得全局并發(fā)隊(duì)列
// 用這個(gè)獲得全局并發(fā)隊(duì)列{dispatch_get_global_queue}
// 用這個(gè)獲得優(yōu)先級(jí){DISPATCH_QUEUE_PRIORITY_DEFAULT}   
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
  1. 并發(fā)隊(duì)列全局并發(fā)隊(duì)列的優(yōu)先級(jí)
define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN // 后臺(tái)

并發(fā)隊(duì)列 + 同步函數(shù) : 不會(huì)開啟線程

Snip20150902_4.png

并發(fā)隊(duì)列 + 異步函數(shù) : 會(huì)開啟線程

Snip20150902_7.png

串行隊(duì)列

GCD中獲得串行有2種途徑

  • 1 - 使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("c.w.z", NULL); 

串行隊(duì)列 + 異步函數(shù) : 會(huì)開啟線程

Snip20150902_10.png

串行隊(duì)列 + 同步函數(shù) : 不會(huì)開啟線程

Snip20150902_12.png

  • 2 - 使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
    主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
    只要是放在主隊(duì)列中的任務(wù),不管你是同步還是異步函數(shù)全都放在主線程中執(zhí)行
dispatch_queue_t queue = dispatch_get_main_queue();

主要是主隊(duì)列:不會(huì)開啟線程

Snip20150902_14.png

各種隊(duì)列的執(zhí)行效果

Snip20150831_56.png

線程間的通訊

從子線程回到主線程

執(zhí)行耗時(shí)的異步操作...

dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         // 回到主線程邀杏,執(zhí)行UI刷新操作
       dispatch_async(dispatch_get_main_queue(), ^{
    });
});

下載圖片的操作

Snip20150902_15.png

延時(shí)執(zhí)行

iOS常見的延時(shí)執(zhí)行有2種方式

// 調(diào)用NSObject的方法
// 2秒后再調(diào)用self的run方法
self performSelector:@selector(run) withObject:nil afterDelay:2.0;

// 使用GCD函數(shù)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)),`                                  
    dispatch_get_main_queue(), ^{
    // 2秒后異步執(zhí)行這里的代碼...       
});

// 使用NSTimer
[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:NO];

只執(zhí)行一次的代碼

// 運(yùn)行時(shí)只執(zhí)行一次
// 使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});

隊(duì)列組

Warning:有這么1種需求:
首先:分別異步執(zhí)行2個(gè)耗時(shí)的操作
其次:等2個(gè)異步操作都執(zhí)行完畢后贫奠,再回到主線程執(zhí)行操作
如果想要快速高效地實(shí)現(xiàn)上述需求唬血,可以考慮用隊(duì)列組

dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)^{
    // 執(zhí)行1個(gè)耗時(shí)的異步操作
});

dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執(zhí)行1個(gè)耗時(shí)的異步操作
});

dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 等前面的異步操作都執(zhí)行完畢后,回到主線程...
});

代碼詳細(xì)實(shí)現(xiàn):

需求:在子線程中下載2張圖片.分別顯示在屏幕的左右.
分析:由于下載圖片屬于耗時(shí)操作,所以要在子線程中操作.等2張圖片都下載好后,在回到主線程加載.

// 點(diǎn)擊屏幕后調(diào)用
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self group];
}

// 隊(duì)列組
- (void)group
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    // 創(chuàng)建一個(gè)隊(duì)列組
    dispatch_group_t group = dispatch_group_create();
    
    // 1.下載圖片1
    dispatch_group_async(group, queue, ^{
        // 圖片的網(wǎng)絡(luò)路徑
        NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
        
        // 加載圖片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成圖片
        self.image1 = [UIImage imageWithData:data];
    });
    
    // 2.下載圖片2
    dispatch_group_async(group, queue, ^{
        // 圖片的網(wǎng)絡(luò)路徑
        NSURL *url = [NSURL URLWithString:@"http://pic38.nipic.com/20140228/5571398_215900721128_2.jpg"];
        
        // 加載圖片
        NSData *data = [NSData dataWithContentsOfURL:url];
        
        // 生成圖片
        self.image2 = [UIImage imageWithData:data];
    });
    
    // 3.將圖片1唤崭、圖片2合成一張新的圖片
    dispatch_group_notify(group, queue, ^{
        // 開啟新的圖形上下文
        UIGraphicsBeginImageContext(CGSizeMake(100, 100));
        
        // 繪制圖片
        [self.image1 drawInRect:CGRectMake(0, 0, 50, 100)];
        [self.image2 drawInRect:CGRectMake(50, 0, 50, 100)];
        
        // 取得上下文中的圖片
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        
        // 結(jié)束上下文
        UIGraphicsEndImageContext();
        
        // 回到主線程顯示圖片
        dispatch_async(dispatch_get_main_queue(), ^{
            // 4.將新圖片顯示出來 
            self.imageView.image = image;
        });
    });
}

顯示結(jié)果

barrier

GCD中還有個(gè)用來執(zhí)行任務(wù)的函數(shù)barrier(柵欄/障礙物)

dispatch_barrier_async(dispatch_queue_t queue>, ^(void)block)
  • 在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的的任務(wù)等它執(zhí)行完之后才會(huì)執(zhí)行
  • 這個(gè)queue不能是全局的并發(fā)隊(duì)列
Paste_Image.png

他會(huì)在執(zhí)行完 barrier上面的1和2后在執(zhí)行barrier后面的3和4


NSOperation:

是在GCD的基礎(chǔ)上進(jìn)行的一層面向?qū)ο蟮陌b.

核心概念:

任務(wù)和隊(duì)列.和GCD基本上是一樣的,只不過更加的面向?qū)ο?用起來比較爽.

NSOperation的作用

  • 配合使用NSOperation和NSOperationQueue也能實(shí)現(xiàn)多線程編程
  • NSOperation:就是任務(wù)
  • NSOperationQueue:就是隊(duì)列

NSOperation的子類

  • NSOperation是個(gè)抽象類拷恨,并不具備封裝操作的能力,必須使用它的子類

使用NSOperation子類的方式有3種:

  1. NSInvocationOperation,
  2. NSBlockOperation,
  3. 自定義子類繼承NSOperation谢肾,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法;

NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟:

  • 先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對象中,
  • 然后將NSOperation對象添加到NSOperationQueue中,
  • 系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來,
  • 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行;

1 - NSInvocationOperation(比較少用)

// 1.創(chuàng)建NSInvocationOperation對象
- (id)initWithTarget:(id)target selector:(SEL)sel object:
- (id)arg;

// 2. 調(diào)用start方法開始執(zhí)行操作
    - (void)start;
一旦執(zhí)行操作腕侄,就會(huì)調(diào)用target的sel方法
  1. 默認(rèn)情況下,調(diào)用了start方法后并不會(huì)開一條新線程去執(zhí)行操作芦疏,而是在當(dāng)前線程同步執(zhí)行操作
  2. 只有將NSOperation放到一個(gè)NSOperationQueue中冕杠,才會(huì)異步執(zhí)行操作


    Snip20150920_62.png

2 - NSBlockOperation

// 1. 創(chuàng)建NSBlockOperation對象
+ (id)blockOperationWithBlock:(void (^)(void))block;

// 2. 通過addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
  • 只要NSBlockOperation封裝的操作數(shù) > 1,就會(huì)異步執(zhí)行操作


    Snip20150920_63.png

3 -自定義NSOperation

  • 首先,在控制器中,將操作添加到隊(duì)列中
  • 然后會(huì)調(diào)用自定義類的- main方法,執(zhí)行- main方法中的任務(wù)
    1.首先新建一個(gè)類,繼承自NSOperation
    2.在.m文件中重寫- main方法 (不是main函數(shù)而是- main方法)
    3.將任務(wù)寫入- main方法中

NSOperationQueue

  • NSOperationQueue的作用
  • NSOperation可以調(diào)用start方法來執(zhí)行任務(wù)眯分,但默認(rèn)是同步執(zhí)行
  • 如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中拌汇,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperation中的操作
// 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;

NSOperationQueue的隊(duì)列類型

主隊(duì)列:
凡是放到了主隊(duì)列的任務(wù)(NSOperation),都會(huì)放到主線程中執(zhí)行
[NSOperationQueue mainQueue];

其他隊(duì)列(串行/并發(fā)):
同時(shí)包含:串行 / 并發(fā)功能
添加這種隊(duì)列中的任務(wù),就會(huì)自動(dòng)放到子線程中執(zhí)行
[NSOperationQueue alloc] init];

最大并發(fā)數(shù)

同時(shí)執(zhí)行的任務(wù)數(shù):比如同時(shí)開3個(gè)線程執(zhí)行3個(gè)任務(wù),并發(fā)數(shù)就是3

// 最大并發(fā)數(shù)的相關(guān)方法
-  (NSInteger)maxConcurrentOperationCount;  
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

隊(duì)列的取消弊决、暫停、恢復(fù)

// 取消隊(duì)列的所有操作
- (void)cancelAllOperations;    

__提示:
也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作

// 暫停和恢復(fù)隊(duì)列(YES代表暫停隊(duì)列魁淳,NO代表恢復(fù)隊(duì)列)
- (void)setSuspended:(BOOL)b; 
- (BOOL)isSuspended;

經(jīng)常通過`- (BOOL)isCancelled`方法檢測操作是否被取消飘诗,對取消做出響應(yīng)

suspended 暫定/掛起

__warning:#cancel     
    官方建議:執(zhí)行完一段耗時(shí)操作的后面最好加上是否點(diǎn)擊了取消的判斷.
    人為控制取消操作.以免,全部執(zhí)行完,還沒有取消掉.

操作優(yōu)先級(jí)

設(shè)置NSOperation在queue中的優(yōu)先級(jí),可以改變操作的執(zhí)行優(yōu)先級(jí)
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;

##優(yōu)先級(jí)的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8

操作依賴

  • NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序

比如一定要讓操作A執(zhí)行完后界逛,才能執(zhí)行操作B昆稿,可以這么寫

// 操作B依賴于操作A
operationB addDependency:operationA;
  • 可以在不同queue的NSOperation之間創(chuàng)建依賴關(guān)系


    Snip20150831_57.png

操作的監(jiān)聽

// 可以監(jiān)聽一個(gè)操作的執(zhí)行完畢
- (void (^)(void))completionBlock;
- (void)setCompletionBlock:(void (^)(void))block;

自定義NSOperation的步驟很簡單

重寫`-(void)main`方法,在里面實(shí)現(xiàn)想執(zhí)行的任

重寫- (void)main方法的注意點(diǎn):

  1. 自己創(chuàng)建自動(dòng)釋放池(因?yàn)槿绻钱惒讲僮飨荩瑹o法訪問主線程的自動(dòng)釋放池)
  2. 經(jīng)常通過-(BOOL)isCancelled方法檢測操作是否被取消溉潭,對取消做出響應(yīng)

GCD和NSOperation的區(qū)別

  • GCD是基于C的底層API
  • NSOperation屬于object-c類。
  • iOS首先引入的是NSOperation少欺,IOS4之后引入了GCD和NSOperationQueue并且其內(nèi)部是用GCD實(shí)現(xiàn)的喳瓣。

NSOperation:

1 - NSOperation擁有更多的函數(shù)可用,具體查看API赞别。
2 - 在NSOperationQueue中畏陕,可以建立各個(gè)NSOperation之間的依賴關(guān)系。
3 - 有KVO仿滔,可以監(jiān)測operation是否
--------------------------正在執(zhí)行isExecuted惠毁、
--------------------------是否結(jié)束isFinished
--------------------------是否取消isCanceld;
4 - NSOperationQueue可以方便的管理并發(fā)崎页、NSOperation之間的優(yōu)先級(jí)鞠绰。

NSOperationQueue的隊(duì)列類型

  • 主隊(duì)列
  • [NSOperationQueue mainQueue]
  • 凡是添加到主隊(duì)列中的任務(wù)(NSOperation),都會(huì)放到主線程中執(zhí)行
  • 非主隊(duì)列(其他隊(duì)列)
  • [[NSOperationQueue alloc] init]
  • 同時(shí)包含了:串行飒焦、并發(fā)功能
  • 添加到這種隊(duì)列中的任務(wù)(NSOperation)蜈膨,就會(huì)自動(dòng)放到子線程中執(zhí)行

GCD:

1 - 主要與block結(jié)合使用。代碼簡潔高效。
2 - GCD也可以實(shí)現(xiàn)復(fù)雜的多線程應(yīng)用丈挟,主要是建立個(gè)個(gè)線程時(shí)間的依賴關(guān)系這類的情況刁卜,但是需要自己實(shí)現(xiàn)相比NSOperation要復(fù)雜。具體使用哪個(gè)曙咽,依需求而定蛔趴。

GCD的隊(duì)列類型

  • 并發(fā)隊(duì)列
  • 全局
  • 自己創(chuàng)建的
  • 串行隊(duì)列
  • 主隊(duì)列
  • 自己創(chuàng)建的

從個(gè)人使用的感覺來看,比較合適的用法是:除了依賴關(guān)系盡量使用GCD例朱,因?yàn)樘O果專門為GCD做了性能上面的優(yōu)化孝情。


GCD實(shí)現(xiàn)單例模式

單例模式 :

其實(shí)就是一種設(shè)計(jì)模式

適用場合

單例模式一般會(huì)在整個(gè)應(yīng)用程序中,共享一份資源(這份資源只需要?jiǎng)?chuàng)建初始化1次)的時(shí)候使用.

比如:

  • 一個(gè)APP中有一個(gè)界面是提供公司的信息的,或者創(chuàng)建賬號(hào)的界面
  • 那么,無論是點(diǎn)擊添加好友或者登錄,都會(huì)跳轉(zhuǎn)到(訪問)創(chuàng)建賬號(hào)這個(gè)界面
  • 那么就可以把這個(gè)界面寫成單例模式,保證屬性以及各種信息都一樣
  • 這樣不僅方便地控制了實(shí)例個(gè)數(shù),并節(jié)約系統(tǒng)資源
比如:
Person *p1 = [Person alloc] init];
Person *p2 = [Person alloc] init];
Person *p3 = [Person alloc] init];
Person *p4 = [Person alloc] init];
Snip20150920_33.png

從上圖我們可以看到:

  • 打印出來的p1,p2,p3,p4的內(nèi)存地址是不一樣的
  • 因?yàn)槊看握{(diào)用alloc會(huì)分配新的內(nèi)存空間.
  • 但是如果實(shí)現(xiàn)了單例模式,就能可以保證在程序運(yùn)行過程中,
  • 無論alloc了多少次,Person這個(gè)類都是同一個(gè)對象.

那么我們怎么樣來實(shí)現(xiàn)單例模式呢?

第一種方法:重寫+ allocWithZone

  • 之所以我們要實(shí)現(xiàn)單例模式,是希望無論alloc了多少次,都只產(chǎn)生一份內(nèi)存
  • 那么我們就要從alloc這里下手
  • 最容易想到的辦法就是在內(nèi)部直接重寫alloc
  • 而且alloc內(nèi)部會(huì)調(diào)用+ allocWithZone這個(gè)方法
  • 無論別人在外界調(diào)用alloc還是調(diào)用+ allocWithZone都會(huì)來到+ allocWithZone這個(gè)方法
  • 所以要重寫+ allocWithZone
    Snip20150920_41.png
Snip20150920_36.png
  • 上圖可以看出我們打印出來的內(nèi)存地址的結(jié)果都是一樣的.

接下來我們來通過打印屬性值來驗(yàn)證下:

Snip20150920_37.png

Snip20150920_39.png

Snip20150920_38.png

第二種方法:[UIApplication sharedApplication]

Snip20150920_42.png

Snip20150920_45.png

Snip20150920_46.png

第三種方法:copy

Snip20150920_48.png

那么,我們應(yīng)該這樣做

Snip20150920_49.png

Snip20150920_50.png
  • 看到這里可能有一個(gè)疑問,這里直接返回_Person的話值不會(huì)為空么?
  • 答案是肯定不會(huì)為空的.
  • 因?yàn)檎{(diào)用copy方法,肯定是有對象在調(diào)用的
  • 所以對象都有值了,那么這個(gè)方法里面肯定也是回有值的

將以上的結(jié)合起來才屬于一套完整的單例模式

Snip20150920_52.png

那么以后一個(gè)工程中可能會(huì)有很多單例,總不能一個(gè)一個(gè)改吧?

那么我們可以將單例弄成宏的形式,以后遇到了直接拖入工程就可以了


Snip20150920_58.png

那么 我們來看下效果:

.h文件

Snip20150920_59.png

.m文件

Snip20150920_60.png

實(shí)現(xiàn)的效果

Snip20150920_61.png

單例模式在ARC\MRC環(huán)境下的寫法有所不同

需要編寫2套不同的代碼

可以用宏判斷是否為ARC環(huán)境

#if __has_feature(objc_arc)
// ARC
#else
// MRC
#endif

ARC中洒嗤,單例模式的實(shí)現(xiàn)

1. 在.m中保留一個(gè)全局的`static`的實(shí)例

static id _instance;

// 重寫allocWithZone:方法箫荡,在這里創(chuàng)建唯一的實(shí)例(注意線程安全)  
+(id)allocWithZone:(struct _NSZone *)zone                      
{
    @synchronized(self) {
        if (!_instance) {                                
        _instance = [super allocWithZone:zone];          
        }
    }   
    return _instance;                                       
}

2. 提供1個(gè)類方法讓外界訪問唯一的實(shí)例
        
+ (instancetype)sharedSoundTool{
    @synchronized(self) {
        if (!_instance) {                                
        _instance = [[self alloc] init];                 
        }
    }
    return _instance;                                       
}

3. 實(shí)現(xiàn)copyWithZone:方法
- (id)copyWithZone:(struct _NSZone *)zone 
        {
            return _instance;
        }

MRC中,單例模式的實(shí)現(xiàn)(比ARC多了幾個(gè)步驟)

// 實(shí)現(xiàn)內(nèi)存管理方法
- (id)retain { 
     return self; 
}

- (NSUInteger)retainCount{ 
 return 1; 
}

- (oneway void)release {
}

- (id)autorelease { 
     return self;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市渔隶,隨后出現(xiàn)的幾起案子羔挡,更是在濱河造成了極大的恐慌,老刑警劉巖间唉,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件绞灼,死亡現(xiàn)場離奇詭異,居然都是意外死亡呈野,警方通過查閱死者的電腦和手機(jī)低矮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來被冒,“玉大人军掂,你說我怎么就攤上這事∽虻浚” “怎么了蝗锥?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長幔戏。 經(jīng)常有香客問我玛追,道長,這世上最難降的妖魔是什么闲延? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任痊剖,我火速辦了婚禮,結(jié)果婚禮上垒玲,老公的妹妹穿的比我還像新娘陆馁。我一直安慰自己,他們只是感情好合愈,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布叮贩。 她就那樣靜靜地躺著击狮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪益老。 梳的紋絲不亂的頭發(fā)上彪蓬,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機(jī)與錄音捺萌,去河邊找鬼档冬。 笑死,一個(gè)胖子當(dāng)著我的面吹牛桃纯,可吹牛的內(nèi)容都是我干的酷誓。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼态坦,長吁一口氣:“原來是場噩夢啊……” “哼盐数!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起伞梯,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤玫氢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后壮锻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琐旁,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年猜绣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敬特。...
    茶點(diǎn)故事閱讀 39,711評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掰邢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出伟阔,到底是詐尸還是另有隱情辣之,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布皱炉,位于F島的核電站怀估,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏合搅。R本人自食惡果不足惜多搀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望灾部。 院中可真熱鬧康铭,春花似錦、人聲如沸赌髓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至夷野,卻和暖如春懊蒸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背悯搔。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工骑丸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鳖孤。 一個(gè)月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓者娱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苏揣。 傳聞我的和親對象是個(gè)殘疾皇子黄鳍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容