跟进项目发现的小问题
这两天再跟进小需求,正好赶上项目要重构,记录一下小细节……
应用前后台标记
typedef NS_ENUM(NSInteger, UIApplicationState) {
UIApplicationStateActive,
UIApplicationStateInactive,
UIApplicationStateBackground
} NS_ENUM_AVAILABLE_IOS(4_0);
就可以记录App的状态,不用在Appdelegate里面做各种标记,比如:
@interface AppDelegate ()
@property (nonatomic, getter=isForeground) BOOL foreground;
此处使用foreground
来标记应用是否在前后台,然后当应用前后台切换的时候设施这个bool
***本地化存储****
使用 NSUserDefaults
应该单独写一个类,全局都从这个类去存储。
现在随便写随便调用,命名也不规范,有使用宏来定义key,有使用static
来定义key. NSUserDefaults 本质是一个plist,所以不应该存储image这样子的大数据。
内存存储,也应该全局统一提供接口,比如使用NSCache
或者NSDictionery
UIAlertView
因为产品近期提出了很多类似于 UIAlertView 弹出顺序的问题,比如:要连着弹出很多个UIAlertView,但是他们都在不同的模块,但是有优先级,触发的时机有可能是通知有可能是用户操作等等。
类似前面的东东,UIAlertView 的弹出也应该全局统一处理,做一个队列,提供先进先出,和优先级的弹出策略。
触摸状态栏,UIScrollView滚动到顶部的策略
不应该在 appdelegate中重写如下方法
#pragma mark - StatusBar
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
CGPoint location = [[[event allTouches] anyObject] locationInView:[self window]];
CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
if (CGRectContainsPoint(statusBarFrame, location)) {
[[NSNotificationCenter defaultCenter] postNotificationName:ptv_notificationStatusBarTappedKey object:nil];
}
}
然后在有 UIScrollView 或者 UIScrollView子类的页面中监听通知去实现,如果一个页面的 UIScrollView 太多,导致点击状态栏没有办法滚动到顶部,应该去实现 UIScrollView的代理方法。
比如:
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView {
if ([_outerDelegate respondsToSelector:_cmd]) {
return [_outerDelegate scrollViewShouldScrollToTop:scrollView];
}
return YES;
}
不需要滚动的view返回NO,一个页面保证一个 UIScrollView 足矣!!
SDWebImage使用问题
- (void)configSDWebimage {
/**
* 由于远程图片为高分辨率,为了减少内存大量飙升,加入非解压的方法来控制,限制缓存
*/
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
图片下载后在非主线程解压然后展示在主线程是优化流畅度的一个重要手法,这也是sd设置这个默认为YES的重要原因。
吧啦吧啦,图片高分辨率,远程……应该能知道哪些页面是所谓高分辨率,然后单独做设置。。
比如:
1、首先在封装的控制器中定义变量用于存储原设置:
static BOOL SDImageCacheOldShouldDecompressImages = YES;
static BOOL SDImagedownloderOldShouldDecompressImages = YES;
2、loadView中保存原设置并且禁用解压缩:
SDImageCache *canche = [SDImageCache sharedImageCache];
SDImageCacheOldShouldDecompressImages = canche.shouldDecompressImages;
canche.shouldDecompressImages = NO;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
SDImagedownloderOldShouldDecompressImages = downloder.shouldDecompressImages;
downloder.shouldDecompressImages = NO;
3、dealloc中恢复原设置:
-(void)dealloc {
SDImageCache *canche = [SDImageCache sharedImageCache];
canche.shouldDecompressImages = SDImageCacheOldShouldDecompressImages;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
downloder.shouldDecompressImages = SDImagedownloderOldShouldDecompressImages;
}
苹果也有给出高清大图的Demo. Large Image Downsizing
总之,不应该为了预防性节省内存,牺牲流畅度等用户体验。
集中打点的问题
现在项目中的打点如下方式
[[DDStatistics sharedInstance] remindDDMessageID:dictionary[@"push_id"]
roomID:roomId
Status:@"3"];
DDStatistics
这个模块在整个项目中有飘来飘去,建议引入切面编程的方式使用配置文件打点,比如引入 aspect
.
某日,产品经理让我找找某个点在哪里打的,比如,10086这个点是哪里的,我就这样子,全局搜索10086,我擦,木有,算了全局搜索 DDStatistics 我擦,还是木有,最后各种排查,发现是传入的某个函数的参数。巴拉巴拉。。。
关于get函数的职责
get函数,我觉得应该只做和需要get对象相关的事情,不应该做其他的事情,不如,在get函数里,把view添加到superView上。
原因有很多,不罗列了,
GCD使用规范
类似这种
- (void)updateEnterForeground {
dispatch_async(dispatch_get_main_queue(), ^{
self.foreground = YES;
});
}
updateEnterForeground
这个函数大部分情况都是在主线程的,为什么内部直接使用这个。。
有时候这么做会延长对象生命周期!,建议性做法类似其他第三方库的:
#ifndef dispatch_main_async_safe
#define dispatch_main_async_safe(block)\
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {\
block();\
} else {\
dispatch_async(dispatch_get_main_queue(), block);\
}
#endif
what ever ,this is safe!!
未完,待续,巴拉巴拉
一个架构师的成长哈哈哈哈