在某些需求下,我們需要建立一個(gè)多路委托協(xié)議,以滿足多處的回調(diào)。比如,一個(gè)網(wǎng)絡(luò)請求數(shù)據(jù)回來,需要通知多個(gè)對象使用。實(shí)現(xiàn)方案其實(shí)很簡單,就是把簡單的代理調(diào)用,變更成一個(gè)代理數(shù)組,在回調(diào)時(shí),遍歷數(shù)組發(fā)送消息即可。
但是要注意,代理是可以被外部釋放的,所以除了我們必須要判斷:
if (self.delegate && [self.delegate respondsToSelector:<#(SEL)#>]) {
...
}
之外,針對多路代理,我們還要對這個(gè)數(shù)組做一個(gè)特殊處理。
我們知道,數(shù)組可以會使對象的引用計(jì)數(shù)增加的。為了保持我們 多路代理數(shù)組 不會印象其內(nèi)元素的引用計(jì)數(shù),我們需要使用 CFArrayCreateMutable 來創(chuàng)建一個(gè) 不會增加引用計(jì)數(shù)的 數(shù)組。
下面直接就是 Nonretaining Array/Dictionary/Set 的代碼了:
NSMutableArray * PDCreateNonRetainingMutableArray()
{
return (__bridge_transfer NSMutableArray *)CFArrayCreateMutable(nil, 0, nil);
}
NSMutableDictionary *PDCreateNonRetainingMutableDictionary()
{
return (__bridge_transfer NSMutableDictionary *)CFDictionaryCreateMutable(nil, 0, nil, nil);
}
NSMutableSet *PDCreateNonRetainingMutableSet()
{
return (__bridge_transfer NSMutableSet *)CFSetCreateMutable(nil, 0, nil);
}
方法是 C 函數(shù),當(dāng)然你也可以封裝成 OC 的函數(shù),純屬個(gè)人喜好。
看到這里,應(yīng)該知道,把這個(gè) 丟到你們對應(yīng)的類別中 就可以愉快使用了,當(dāng)然丟代碼里也行,反正我會不接你的鍋。
測試用例:
NSObject *obj = [NSObject new];
NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));
NSMutableArray *array = @[].mutableCopy;
[array addObject:obj];
NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));
NSMutableArray *nonretainingArray = PDCreateNonRetainingMutableArray();
[nonretainingArray addObject:obj];
NSLog(@"Retain count is %ld", CFGetRetainCount((__bridge CFTypeRef)obj));
結(jié)果:
Retain count is 1
Retain count is 2
Retain count is 2
完美。
7月4日更新:
看到有人提到了 NSPointerArray ,這里也就寫上來,為何我沒有使用 NSPointerArray。
讓我們瞅一眼 NSPointerArray 的使用
NSPointerArray *array = [NSPointerArray weakObjectsPointerArray];
[array addPointer:(__bridge void *)obj];
這貨跟上面一樣丑。那么使用起來,肯定會進(jìn)行一輪的封裝。
讓我們再看看性能:性能檢查的宏實(shí)現(xiàn)在這里
以下為性能測試
寫入測試(每 10^2 次寫入為一組參考值,重復(fù) 10^5 次取平均值):
- (void)measure
{
NSObject *obj = [NSObject new];
PDMeasure(@"NSMutableArray 寫入速度", {
NSMutableArray *mutableArray = @[].mutableCopy;
for (int i = 0; i < 100; i++)
{
[mutableArray addObject:obj];
}
})
PDMeasure(@"NSNonretainingMutableArray 寫入速度", {
NSMutableArray *nonretainingArray = PDCreateNonRetainingMutableArray();
for (int i = 0; i < 100; i++)
{
[nonretainingArray addObject:obj];
}
})
PDMeasure(@"NSPointerArray 寫入速度", {
NSPointerArray *pointerArray = [NSPointerArray weakObjectsPointerArray];
for (int i = 0; i < 100; i++)
{
[pointerArray addPointer:(__bridge void *)obj];
}
})
}
測試結(jié)果輸出:
[P] <ViewController|NSMutableArray 寫入速度> The average runtime for operation is 10479 ns.
[P] <ViewController|NSNonretainingMutableArray 寫入速度> The average runtime for operation is 4822 ns.
[P] <ViewController|NSPointerArray 寫入速度> The average runtime for operation is 40685 ns.
讀取速度幾乎相同,這里就不貼代碼和結(jié)果了。
以上為性能測試
測試結(jié)果是:
寫入速度 CFArray 實(shí)現(xiàn)的 NonRetainMutableArray 比 NSMutableArray 快約 2 倍,比 NSPointerArray 快約 10 倍。
讀取速度幾乎相同。
既然都封裝后再使用的,就選個(gè)性能好的吧。
以上。