這個(gè)文章的前置文章:LNDanmakuMaster
LNDanmakuPool是LNDanmakuMaster針對彈幕場景提出的復(fù)用方案贫堰,與UICollectionView/UITableView的復(fù)用邏輯很相似酝陈,為任意NSObject類型打標(biāo)簽,并通過標(biāo)簽進(jìn)行NSObject類型的存取。
LNDanmakuPurePool
如果我們想實(shí)現(xiàn)一個(gè)可以通過不同標(biāo)簽存取不同對象的池子,首先需要實(shí)現(xiàn)一個(gè)只能存取一種固定類型的池子,這個(gè)池子就是LNDanmakuPurePool:
@interface LNDanmakuPurePool : NSObject
@property (nonatomic, assign) NSInteger maxCapacity;
@property (nonatomic, assign) Class targetClass;
@property (nonatomic, copy) NSString *poolKey;
- (void)saveObj:(NSObject *)obj;
- (NSObject *)getObj;
- (void)clearPurePool;
@end
這個(gè)池子指定了key與Class的對應(yīng)關(guān)系,只有Key類型符合要求時(shí),才可以進(jìn)行存取操作车摄;且存取對象的類型固定為targetClass類型。除此之外,這個(gè)池子還定義了最大存儲(chǔ)數(shù)量和清空方法练般;存儲(chǔ)時(shí)矗漾,如果當(dāng)前已存儲(chǔ)對象個(gè)數(shù)已超過最大容量,則不會(huì)繼續(xù)存儲(chǔ)薄料;反之敞贡,獲取時(shí),如果當(dāng)前池子已空摄职,則會(huì)重新創(chuàng)建對象返回:
- (void)saveObj:(NSObject *)obj
{
if (self.poolMSet.count > self.maxCapacity) {
while (self.poolMSet.count > self.maxCapacity) {
[self.poolMSet removeObject:self.poolMSet.anyObject];
}
} else if (self.poolMSet.count == self.maxCapacity) {
//Fulled .
} else {
if ([obj isKindOfClass:self.targetClass] && [[obj danmakuPoolKey] isEqualToString:self.poolKey]) {
[self.poolMSet addObject:obj];
}
}
}
存儲(chǔ)時(shí)會(huì)校驗(yàn)obj類型和key是否都合法誊役,obj.danmakuPoolKey是在這個(gè)池子創(chuàng)建一個(gè)對象時(shí)進(jìn)行賦值的,也是“這個(gè)對象屬于這個(gè)池子”的標(biāo)志屬性(多余的判斷為防止在一些異常情況下也能正常工作):
- (NSObject *)getObj
{
NSObject *resultObj = nil;
while (self.poolMSet.count > 0) {
NSObject *obj = [self.poolMSet anyObject];
if ([obj isKindOfClass:self.targetClass] && [obj.danmakuPoolKey isEqualToString:self.poolKey]) {
resultObj = obj;
[self.poolMSet removeObject:obj];
break;
} else {
[self.poolMSet removeObject:obj];
}
}
if (resultObj) {
return resultObj;
} else {
resultObj = [[self.targetClass alloc] init];
[resultObj setDanmakuPoolKey:self.poolKey];
return resultObj;
}
}
LNDanmakuPool
PurePool已經(jīng)定義好了一種純粹的池子供我們調(diào)用谷市,Pool就可以通過維護(hù)多個(gè)PurePool來實(shí)現(xiàn)多種對象的存取了蛔垢,Pool的方法相當(dāng)簡練:
@interface LNDanmakuPool : NSObject
- (void)registerClass:(Class)class forKey:(NSString *)key;
- (NSObject *)instanceForKey:(NSString *)key;
- (void)saveInstance:(NSObject *)instance;
@end
Pool的內(nèi)部維護(hù)了一個(gè)Key和PurePool的映射,注冊過程會(huì)為key創(chuàng)建好一個(gè)class類型的PurePool迫悠,當(dāng)用戶存放或獲取時(shí)通過這個(gè)映射找到對應(yīng)的PurePool進(jìn)行存扰羝帷:
@interface LNDanmakuPool ()
@property (nonatomic, strong) NSMutableDictionary <NSString *, LNDanmakuPurePool *> *poolMDic;
@end
存取哪些NSObject?
通常创泄,我們?yōu)槊總€(gè)Player配備了一個(gè)專門的Pool用來復(fù)用艺玲,通常情況下NSAttributes繼承自NSObject,類似于一個(gè)包裝袋鞠抑,它是一次性的且開銷很小饭聚,不需要進(jìn)行復(fù)用;customObj是業(yè)務(wù)方規(guī)定的彈幕模型搁拙,本身就是不固定的id類型秒梳,復(fù)用業(yè)務(wù)模型是不太現(xiàn)實(shí)的;因此箕速,這里強(qiáng)調(diào)的復(fù)用與UICollectionView一樣酪碘,是UI層面的復(fù)用:UIView/CAlayer,如果使用方的UIView層級比較復(fù)雜弧满,且有很多布局邏輯婆跑、點(diǎn)擊事件等此熬,LNDanmakuMaster推薦從Player的池子中獲取這些UI組件庭呜,這樣取出的UI組件都被打上對應(yīng)池子的標(biāo)簽,并會(huì)在LNDanmakuMaster的各種時(shí)機(jī)自動(dòng)回收(任意NSAttributes失效之前犀忱,這個(gè)過程不需要手動(dòng)處理募谎,只要是register過且從Pool中獲取到的都可以被回收),這些時(shí)機(jī)包括:
- Dispatcher從隊(duì)列中丟棄一個(gè)Attributes時(shí)
- Dispatcher被清理時(shí)
- 播放完阴汇,已經(jīng)卸載一個(gè)Attributes時(shí)
- 當(dāng)前Player在非播放中狀態(tài)下数冬,插入Attributes失敗時(shí)
Tips
雖然LNDanmakuPlayer提供了Pool來獲取一個(gè)UI組件,但并沒有指定必須使用這個(gè)UI組件做哪些工作;因此拐纱,使用者可以從Pool中獲取一個(gè)UI組件铜异,但不把它放在播放器中播放,這樣就從LNDanmakuPlayer的池子里“偷走”了一個(gè)UI組件秸架,因?yàn)闆]有經(jīng)過彈幕周期的組件是不會(huì)被回收的揍庄。