Skip to content

Commit d85bf3e

Browse files
committed
使用NSMapTable替换NSDictionary存储对象
使用NSMapTable替换NSDictionary存储对象,实现对象弱引用,详情讨论见:https://github.com/iphone5s olo/PYTheme/issues/2
1 parent 2ed65f7 commit d85bf3e

File tree

2 files changed

+77
-43
lines changed

2 files changed

+77
-43
lines changed

PYTheme/NSObject+PYThemeExtension.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ typedef void(^PYThemeImageSettingBlock)(const NSArray<id> *objects);
2424
* 如果数组中某个参数为nil,需包装为 [NSNull null] 对象再添加到数组中
2525
*/
2626
- (void)py_addToThemeColorPoolWithSelector:(SEL)selector objects:(NSArray<id> *)objects;
27+
/**
28+
* 从主题色池移除
29+
* selector : 执行方法
30+
*/
31+
- (void)py_removeFromThemeColorPoolWithSelector:(SEL)selector;
2732
/**
2833
* 添加到主题色池
2934
* propertyName : 属性名

PYTheme/NSObject+PYThemeExtension.m

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
@implementation NSObject (PYThemeExtension)
1515

1616
/** 主题颜色池 */
17-
static NSMutableArray<NSDictionary *> *_themeColorPool;
17+
static NSMutableArray<NSMapTable *> *_themeColorPool;
1818
/** 当前主题色 */
1919
static UIColor *_currentThemeColor;
2020

@@ -169,54 +169,80 @@ - (void)py_addToThemeColorPoolWithSelector:(SEL)selector objects:(NSArray *)obje
169169
if ([self isMemberOfClass:appearanceClass]) return;
170170
// 键:对象地址+方法名 值:对象
171171
NSString *pointSelectorString = [NSString stringWithFormat:@"%p%@", self, NSStringFromSelector(selector)];
172-
NSDictionary *dic = @{ pointSelectorString : self,
173-
PYTHEME_COLOR_ARGS_KEY : objects };
172+
// 采用NSMapTable存储对象,使用弱引用
173+
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn valueOptions:NSMapTableWeakMemory];
174+
[mapTable setObject:self forKey:pointSelectorString];
175+
[mapTable setObject:objects forKey:PYTHEME_COLOR_ARGS_KEY];
174176
// 判断是否已经在主题色池中
175-
if (![[self themeColorPool] containsObject:dic]) { // 不在主题色池中
176-
[[self themeColorPool] addObject:dic];
177-
if (_currentThemeColor) { // 已经设置主题色,直接设置
178-
[self py_performSelector:selector withObjects:objects];
177+
for (NSMapTable *subMapTable in [[self themeColorPool] copy]) {
178+
if ([[subMapTable description] isEqualToString:[mapTable description]]) { // 存在,直接返回
179+
return;
179180
}
180181
}
182+
// 不存在,添加主题色池中
183+
[[self themeColorPool] addObject:mapTable];
184+
if (_currentThemeColor) { // 已经设置主题色,直接设置
185+
[self py_performSelector:selector withObjects:objects];
186+
}
181187
}
182188

183189
/**
184-
* 添加到主题色池
185-
* propertyName : 属性名
190+
* 从主题色池移除
191+
* selector : 执行方法
186192
*/
187-
- (void)py_addToThemeColorPool:(NSString *)propertyName
193+
- (void)py_removeFromThemeColorPoolWithSelector:(SEL)selector
188194
{
189195
// 如果对象为_UIAppearance,直接返回
190196
Class appearanceClass = NSClassFromString(@"_UIAppearance");
191197
if ([self isMemberOfClass:appearanceClass]) return;
192-
// 键:对象地址+属性名 值:对象
193-
NSString *pointString = [NSString stringWithFormat:@"%p%@", self, propertyName];
194-
NSDictionary *dic = @{ pointString : self };
195-
// 判断是否已经在主题色中
196-
if (![[self themeColorPool] containsObject:dic]) { // 不在主题色池中
197-
[[self themeColorPool] addObject:dic];
198-
if (_currentThemeColor) { // 已经设置主题色,直接设置
199-
[self setValue:_currentThemeColor forKey:propertyName];
200-
}
201-
}
202-
// 遍历主题色池(移除应该被回收的对象)
203-
for (NSDictionary *dict in [[self themeColorPool] copy]) {
198+
199+
// 键:对象地址+方法名 值:对象
200+
NSString *pointSelectorString = [NSString stringWithFormat:@"%p%@", self, NSStringFromSelector(selector)];
201+
// 判断是否已经在主题色池中
202+
for (NSMapTable *subMapTable in [[self themeColorPool] copy]) {
204203
// 取出key
205204
NSString *objectKey = nil;
206-
for (NSString *key in [dict allKeys]) {
205+
// 获取mapTable中所有key
206+
NSEnumerator *enumerator = [subMapTable keyEnumerator];
207+
NSString *key;
208+
while (key = [enumerator nextObject]) {
207209
if (![key isEqualToString:PYTHEME_COLOR_ARGS_KEY]) {
208210
objectKey = key;
209211
break;
210212
}
211213
}
212-
// 取出对象
213-
id object = [dict valueForKey:objectKey];
214-
// 取出对象的引用计数
215-
NSInteger retainCount = [[object valueForKey:@"retainCount"] integerValue];
216-
if (retainCount == 2) { // 对象应该被回收了
217-
[[self themeColorPool] removeObject:dict];
214+
if([objectKey isEqualToString:pointSelectorString]) { // 存在,移除
215+
[[self themeColorPool] removeObject:subMapTable];
216+
return;
217+
}
218+
}
219+
}
220+
221+
/**
222+
* 添加到主题色池
223+
* propertyName : 属性名
224+
*/
225+
- (void)py_addToThemeColorPool:(NSString *)propertyName
226+
{
227+
// 如果对象为_UIAppearance,直接返回
228+
Class appearanceClass = NSClassFromString(@"_UIAppearance");
229+
if ([self isMemberOfClass:appearanceClass]) return;
230+
// 键:对象地址+属性名 值:对象
231+
NSString *pointString = [NSString stringWithFormat:@"%p%@", self, propertyName];
232+
// 采用NSMapTable存储对象,使用弱引用
233+
NSMapTable *mapTable = [NSMapTable mapTableWithKeyOptions:NSMapTableCopyIn valueOptions:NSMapTableWeakMemory];
234+
[mapTable setObject:self forKey:pointString];
235+
// 判断是否已经在主题色池中
236+
for (NSMapTable *subMapTable in [[self themeColorPool] copy]) {
237+
if ([[subMapTable description] isEqualToString:[mapTable description]]) { // 存在,直接返回
238+
return;
218239
}
219240
}
241+
// 不存在,添加主题色池中
242+
[[self themeColorPool] addObject:mapTable];
243+
if (_currentThemeColor) { // 已经设置主题色,直接设置
244+
[self setValue:_currentThemeColor forKey:propertyName];
245+
}
220246
}
221247

222248
/**
@@ -231,10 +257,14 @@ - (void)py_removeFromThemeColorPool:(NSString *)propertyName
231257

232258
// 键:对象地址+属性名 值:对象
233259
NSString *pointString = [NSString stringWithFormat:@"%p%@", self, propertyName];
234-
NSDictionary *dic = @{ pointString : self };
235260
// 判断是否已经在主题色池中
236-
if ([[self themeColorPool] containsObject:dic]) { // 在主题色池中
237-
[[self themeColorPool] removeObject:dic];
261+
for (NSMapTable *subMapTable in [[self themeColorPool] copy]) {
262+
// 获取mapTable中所有key
263+
NSEnumerator *enumerator = [subMapTable keyEnumerator];
264+
if([[enumerator nextObject] isEqualToString:pointString]) { // 存在,移除
265+
[[self themeColorPool] removeObject:subMapTable];
266+
return;
267+
}
238268
}
239269
}
240270

@@ -246,20 +276,26 @@ - (void)py_setThemeColor:(UIColor *)color
246276
{
247277
_currentThemeColor = color;
248278
// 遍历缓主题池,设置统一主题色
249-
for (NSDictionary *dict in [_themeColorPool copy]) {
279+
for (NSMapTable *mapTable in [_themeColorPool copy]) {
250280
// 取出key
251281
NSString *objectKey = nil;
252-
for (NSString *key in [dict allKeys]) {
282+
// 获取mapTable中所有key
283+
NSEnumerator *enumerator = [mapTable keyEnumerator];
284+
NSString *key;
285+
while (key = [enumerator nextObject]) {
253286
if (![key isEqualToString:PYTHEME_COLOR_ARGS_KEY]) {
254287
objectKey = key;
255288
break;
256289
}
257290
}
291+
if (!key) { // 如果key为空,则mapTable 为空,移除mapTable
292+
[_themeColorPool removeObject:mapTable];
293+
}
258294
// 取出对象
259-
id object = [dict valueForKey:objectKey];
295+
id object = [mapTable objectForKey:objectKey];
260296
if ([objectKey containsString:@":"]) { // 方法
261297
// 取出参数
262-
NSArray *args = dict[PYTHEME_COLOR_ARGS_KEY];
298+
NSArray *args = [mapTable objectForKey:PYTHEME_COLOR_ARGS_KEY];
263299
// 取出方法
264300
NSString *selectorName = [objectKey substringFromIndex:[[NSString stringWithFormat:@"%p", object] length]];
265301
SEL selector = NSSelectorFromString(selectorName);
@@ -295,13 +331,6 @@ - (void)py_addToThemeImagePool
295331
if (![[self themeImagePool] containsObject:self]) { // 不在主题图片池中
296332
[[self themeImagePool] addObject:self];
297333
}
298-
// 遍历主题图片池(移除应该被回收的对象)
299-
for (id object in [self themeImagePool]) {
300-
NSInteger retainCount = [[object valueForKey:@"retainCount"] integerValue];
301-
if (retainCount == 2) { // 对象应该被回收了
302-
[[self themeImagePool] removeObject:self];
303-
}
304-
}
305334
}
306335

307336
/** 从主题图片池中移除 */

0 commit comments

Comments
 (0)