[實踐]iOS數組Delegate解引用實踐

更好的方式:


NSHashTable == 弱引用版的NSSet
NSMapTable == 弱引用版的NSDictionary數組

舊文


背景:

有一個單例類, 提供了定位服務, 而後經過數組來持有代理對象, 以達到多個代理效果.atom

問題:

那麼問題來了, 數組是強引用持有對象的, 因此會形成持有的對象不能釋放問題. (例如VC已經關閉, 可是還被數組持有, 因此不會走dealloc方法).net

解決思路:

建立一個NSObject對象(暫命名爲weakObject), weak持有代理對象(vc), 而後單例類的數組持有該weakObject對象. 這樣vc就能正常釋放了.代理

注意點:code

  1. 實際上是把強持有vc的問題轉換給了weakObject, 因此數組中weakObject對象仍是會愈來愈多. 因此須要在調用weakObject.delegate時進行判斷. 若是weakObject.delegate==nil,則把weakObject從單例類的數組中移除.對象

  2. 從數組中移除元素時, 不能再for循環內進行, 不然會crash. 可以使用NSArray的enumerateObjectsUsingBlock方法來進行遍歷移除. 參考: http://blog.csdn.net/wzf906819823/article/details/47069205blog

DEMO:

單例類:事件

@interface SYLocationManager : NSObject

/**
*  添加監聽者
*
*  @param listener 監聽者
*/
- (void)addListener:(id<SYLocationListener>)listener;

@end

@implementation SYLocationManager

- (void)addListener:(id<SYLocationListener>)listener {
    if (!_listenerList) {
        _listenerList = [[NSMutableArray alloc] init];
    }

    SYLocationWeakTarget *weakTarget = [[SYLocationWeakTarget alloc] init];
    weakTarget.delegate = listener;

    [_listenerList addObject:weakTarget];
}

//  事件回調
- (void)notifyLocateSuccess {
    [self removeAllIncalidDelegate];

    for (SYLocationWeakTarget *weakTarget in _listenerList) {

        if ([weakTarget.delegate respondsToSelector:@selector(locateResult:)]) {
            [weakTarget.delegate locateResult:TRUE];
        }
    }
}

// 移除已釋放的代理對象
- (void)removeAllIncalidDelegate {

    [_listenerList enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        SYLocationWeakTarget *target = (SYLocationWeakTarget *)obj;
        if (target.delegate == nil) {
            [_listenerList removeObject:target];
        }
    }];
}

@end

弱引用類rem

@interface SYLocationWeakTarget : NSObject

@property (nonatomic, weak) id<SYLocationListener> delegate;

@end
相關文章
相關標籤/搜索