需求
最近做一個項目中,有個需求,所有網絡請求,都不顯示 NetworkActvityIndicator(也就是狀態欄里旋轉的小圈圈).
解決過程1:
全局搜索 NetworkIndicator 關鍵字, 把所有涉及 NetworkIndicator 的代碼去除,比如 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
。
測試并發現新問題
所有界面都不再顯示NetworkActvityIndicator了,唯獨一個播放視頻的界面依然顯示。
猜想: 第三方庫引發的問題
無論是哪些第三方庫,正常情況都會通過 setNetworkActivityIndicatorVisible 來 顯示狀態欄小圈圈。
驗證過程1
通過繼承 UIApplication 來重寫了 setNetworkActivityIndicatorVisible 方法。(如何繼承UIApplication,請看這里)并把斷點打在這個方法體內。
測試了正常調用 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
是會觸發斷點的。但是唯獨那個視頻界面,沒有觸發該斷點的情況下,正常顯示小圈圈。
驗證過程2
通過 KVO 監聽 UIApplication 的 networkActivityIndicatorVisible 屬性,結果還是和 驗證過程1 的情況一樣。
正常調用 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
是會觸發監聽, 唯獨那個視頻界面,沒有觸發監聽的情況下,正常顯示小圈圈。
所以, 視頻界面里顯示的小圈圈,肯定不是通過常規調用 setNetworkActivityIndicatorVisible
方法顯示出來的。
更新猜想: 第三方庫引發的問題,并且不是通過常規方法調用
驗證過程3
顯示小圈圈的情況下,分析了該界面的視圖層級,發現在 statusBar 上,有 類型為UIActivityIndicatorView的視圖存在(并且怪異的存在了兩個)。
那正常情況下,通過 [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
顯示小圈圈時,視圖層級是如何的呢? 通過分析驗證, 也是一樣的。
層級都是 UIStatusBarView -> UIStatusBarForegroundView -> UIStatusBarActivityItemView -> UIActivityIndicatorView
想到解決方案:
既然小圈圈都是 UIActivityIndicatorView 類型的視圖,而 UIActivityIndicatorView 開始動畫常規都是調用 startAnimation
方法。
那何不使用黑魔法(method swizzling)來重寫它的 startAnimation
方法,
判斷它的superView是否為 “UIStatusBarActivityItemView”類型,如果是,則直接跳出。否則,執行原有的 startAnimation方法。
Talk is cheap. Show me the code.
以下是 .m 文件的代碼
@implementation UIActivityIndicatorView (HideNetworkActivityIndicator)+ (void)load {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{Class class = [self class];SEL originalSelector = @selector(startAnimating);SEL swizzledSelector = @selector(xxx_startAnimating);Method originalMethod = class_getInstanceMethod(class, originalSelector);Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);// When swizzling a class method, use the following:// Class class = object_getClass((id)self);// ...// Method originalMethod = class_getClassMethod(class, originalSelector);// Method swizzledMethod = class_getClassMethod(class, swizzledSelector);BOOL didAddMethod =class_addMethod(class,originalSelector,method_getImplementation(swizzledMethod),method_getTypeEncoding(swizzledMethod));if (didAddMethod) {class_replaceMethod(class,swizzledSelector,method_getImplementation(originalMethod),method_getTypeEncoding(originalMethod));} else {method_exchangeImplementations(originalMethod, swizzledMethod);}});
}#pragma mark - Method Swizzling- (void)xxx_startAnimating{if (self.superview != nil && [NSStringFromClass([self.superview class]) isEqualToString: @"UIStatusBarActivityItemView"]) {NSLog(@"黑魔法禁止狀態欄的loading顯示: %@", self);} else {[self xxx_startAnimating];}}@end
成功了!!!
(在xxx_startAnimation方法體內打斷點,程序進入視頻播放界面,觸發斷點,看調用棧,果然是第三方庫引發的問題。)
參考資料:https://nshipster.cn/method-s...