1.怎么對接口返回的空數(shù)據(jù)null做數(shù)據(jù)保護瓣喊?
網(wǎng)上有個很牛逼的第三方框架NullSafe涌萤,可以處理iOS開發(fā)中服務器返回null引起的崩潰。NullSafe是NSNull上的一個簡單類別,它為無法識別的消息返回nil而不是拋出異常御吞。底層現(xiàn)實的原理是同runtime對方法的轉(zhuǎn)發(fā)進行最后的攔截儿子,在forwardInvocation方法里面使target變?yōu)閚il瓦哎,因為nil在oc中是有效的指針。要使用NullSafe,只需將NullSafe.m文件拖到項目中即可蒋譬。NullSafe將在運行時自動加載割岛,您不需要在代碼中包含任何頭文件。
2.無侵入的界面埋點和事件埋點實現(xiàn)思路犯助?
我們都知道癣漆,在 iOS 開發(fā)中最常見的三種埋點,就是對頁面進入次數(shù)剂买、頁面停留時間惠爽、點擊事件的埋點。對于這三種常見情況雷恃,我們都可以通過運行時方法替換技術(shù)來插入埋點代碼以實現(xiàn)無侵入的埋點方法疆股。
頁面進入次數(shù)、頁面停留時間都需要對 UIViewController 生命周期進行埋點倒槐,你可以創(chuàng)建一個 UIViewController 的 Category
@implementation UIViewController (logger)
+ (void)load {
? ? static dispatch_once_t onceToken;
? ? dispatch_once(&onceToken, ^{
? ? ? ? // 通過 @selector 獲得被替換和替換方法的 SEL旬痹,作為 SMHook:hookClass:fromeSelector:toSelector 的參數(shù)傳入
? ? ? ? SEL fromSelectorAppear = @selector(viewWillAppear:);
? ? ? ? SEL toSelectorAppear = @selector(hook_viewWillAppear:);
? ? ? ? [SMHook hookClass:self fromSelector:fromSelectorAppear toSelector:toSelectorAppear];
? ? ? ? SEL fromSelectorDisappear = @selector(viewWillDisappear:);
? ? ? ? SEL toSelectorDisappear = @selector(hook_viewWillDisappear:);
? ? ? ? [SMHook hookClass:self fromSelector:fromSelectorDisappear toSelector:toSelectorDisappear];
? ? });
}
- (void)hook_viewWillAppear:(BOOL)animated {
? ? // 先執(zhí)行插入代碼,再執(zhí)行原 viewWillAppear 方法
? ? [self insertToViewWillAppear];
? ? [self hook_viewWillAppear:animated];
}
- (void)hook_viewWillDisappear:(BOOL)animated {
? ? // 執(zhí)行插入代碼讨越,再執(zhí)行原 viewWillDisappear 方法
? ? [self insertToViewWillDisappear];
? ? [self hook_viewWillDisappear:animated];
}
- (void)insertToViewWillAppear {
? ? // 在 ViewWillAppear 時進行日志的埋點
? ? [[[[SMLogger create]
? ? ? message:[NSString stringWithFormat:@"%@ Appear",NSStringFromClass([self class])]]
? ? ? classify:ProjectClassifyOperation]
? ? save];
}
- (void)insertToViewWillDisappear {
? ? // 在 ViewWillDisappear 時進行日志的埋點
? ? [[[[SMLogger create]
? ? ? message:[NSString stringWithFormat:@"%@ Disappear",NSStringFromClass([self class])]]
? ? ? classify:ProjectClassifyOperation]
? ? save];
}
@end
可以看到两残,Category 在 +load() 方法里使用了SMHook 進行方法替換,在替換的方法里執(zhí)行需要埋點的方法 [self insertToViewWillAppear]把跨。
對于點擊事件來說人弓,我們也可以通過運行時方法替換的方式進行無侵入埋點,這里最主要的工作是着逐,找到這個點擊事件的方法崔赌,sendAction:to:forEvent:然后在 +load() 方法使用 SMHook 替換成為你定義的方法。完整代碼實現(xiàn)如下:
+ (void)load {
? ? static dispatch_once_t onceToken;
? ? dispatch_once(&onceToken, ^{
? ? ? ? // 通過 @selector 獲得被替換和替換方法的 SEL耸别,作為 SMHook:hookClass:fromeSelector:toSelector 的參數(shù)傳入
? ? ? ? SEL fromSelector = @selector(sendAction:to:forEvent:);
? ? ? ? SEL toSelector = @selector(hook_sendAction:to:forEvent:);
? ? ? ? [SMHook hookClass:self fromSelector:fromSelector toSelector:toSelector];
? ? });
}
- (void)hook_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
? ? [self insertToSendAction:action to:target forEvent:event];
? ? [self hook_sendAction:action to:target forEvent:event];
}
- (void)insertToSendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
? ? // 日志記錄
? ? if ([[[event allTouches] anyObject] phase] == UITouchPhaseEnded) {
? ? ? ? NSString *actionString = NSStringFromSelector(action);
? ? ? ? NSString *targetName = NSStringFromClass([target class]);
? ? ? ? [[[SMLogger create] message:[NSString stringWithFormat:@"%@ %@",targetName,actionString]] save]健芭;
3.重寫了屬性的set方法和get方法,會怎么樣秀姐?要怎么解決慈迈?
寫了get和set方法之后@property默認生成的@synthesize就不會起作用了,這也就意味著你的類不會自動生成出來實例變量了省有,你就必須要自己聲明實例變量,
4.怎么通過view去找到對應的控制器痒留?
可以通過一個第三方框架PSRouter去獲取,
找到當前view所在的控制器- (UIViewController *)findViewController:(UIView *)sourceView
{
? ? id target=sourceView;
? ? while (target) {
? ? ? ? target = ((UIResponder *)target).nextResponder;
? ? ? ? if ([target isKindOfClass:[UIViewController class]]) {
? ? ? ? ? ? break;
? ? ? ? }
? ? }
? ? return target;
}
5.怎么查找兩個view的公共父視圖
首先我們寫一個函數(shù)去找到一個View的所有父view蠢沿,并返回一個數(shù)組伸头,這個數(shù)組存儲著這條鏈上的所有view。
-(NSArray*)superViews:(UIView *)viewA{
? ? if (viewA == nil) {
? ? ? ? return @[];
? ? }
? ? NSMutableArray* superViewsArray = [NSMutableArray array];
? ? if (viewA != nil) {
? ? ? ? [superViewsArray addObject:viewA];
? ? ? ? viewA = viewA.superview;
? ? }
? ? return [superViewsArray copy];
}
//我們把兩個view的所有父view都存在了數(shù)組里舷蟀,那么想要比較兩個view最近的根節(jié)點其實就是從頭比較兩個數(shù)組熊锭,看第一個公共元素是什么弧轧,就是我們要找的第一個公共父view啦!
-(UIView*)commonView:(UIView*)viewA andView:(UIView*)viewB{
? ? NSArray* superViewA = [self superViews:viewA];
? ? NSArray* superViewB = [self superViews:viewB];
? ? NSSet* view2Set = [NSSet setWithArray:superViewB];
? ? UIView* resultView = [[UIView alloc] init];
? ? for (NSUInteger i =0; i<view2Set.count; i++) {
? ? ? ? if ([view2Set containsObject:superViewA[i]]) {
? ? ? ? ? ? resultView = superViewA[i];
? ? ? ? ? ? return resultView;// 找到了就馬上返回碗殷,不要再繼續(xù)找了
? ? ? ? }
? ? }
? ? return nil;