算来自己工作4年有余,一直在iOS开发中重复造车轮。最近总结下自己在工作中的新知识,以后不定期更新。
一、按钮防重复点击
这个范畴不光是按钮了,有很多中情况,比如按钮重复点击,网络重复请求,跳转页面重复等很多情况,大概说以下之前我的解决思路。
1.按钮重复点击常见的思路是控制按钮的交互状态,也就是按钮交互功能的开和关(enable属性),但是前提就是你需要获得开启和状态关闭的状态,手动处理。第二种思路是利用可控延迟,让之前重复点击的功能无效化。在搜索中经常见到,就是输入文字的时候不访问网络,输入完成停止下来以后在访问,调用方法为:
//取消调用的方法
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(click) object:nil];
//半秒后调用方法
[self performSelector:@selector(click) withObject:nil afterDelay:0.5];
2.网络重复请求我们常见的思路就是在访问网络开始和结束增加hud,或者专门建立一个网络请求的页面(view)盖在屏幕上,遮挡其他控件。
3.今天着重说下iOS页面push跳转这种情况,这种情况一般不做处理,但是狂点的话,经常造成重复进入页面的问题,很多大的App也存在这个情况,我用微信狂点跳转页面,出现几率还是挺高的。自己总结了一个思路,思路如下:
如果你的Navigation是自定义的,可以重写-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated方法,在此方法中做处理
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
if (![[super topViewController] isKindOfClass:[viewController class]]) {
[super pushViewController:viewController animated:animated];
}
} 这样可以有效的防止重复进入一个一样的controller,但是也有弊端,如果你的需求就是要重复进入一个类,就是被这块的逻辑拦截。
二、iOS中App内部的数据在外部获取
这个需求不太常见,但是很有用,常见的情况,项目A中的字符串@"123"如何能被项目B中获取,我整理几个我的思路:
1.利用系统自身的复制粘贴版,项目A中复制一段可见于UI上的数据,在另一个App中粘贴,需求也很明确,就是需要这个元素存在在UI上。
2.写入沙盒的数据提取,直接放代码吧
//存入一段字符串
_path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"file.txt"];
[@"哈哈哈" writeToFile:_path atomically:YES encoding:NSUTF8StringEncoding error:nil] ? NSLog(@"成功") : NSLog(@"失败");
//打开这个类
UIDocumentInteractionController *documentVC = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:_path]];
documentVC.UTI = @"com.microsoft.word.doc";
documentVC.delegate = self;
[documentVC presentOpenInMenuFromRect:self.view.bounds inView:self.view animated:YES];

这是模拟器状态,真机中会多大量的选项,备忘录、QQ、微信等等很多,思路是把沙盒中的数据借用其他工具执行,我们有个需求就是下载word、excel文档,然后再通过微信打开,就是这个思路
3.keychain,这个思路我自己思考了以下感觉是可以的,但是没有实际用过。
三、利用runtime获取网络状态
我们一般获取网络状态都是Reachability,AFNetworking等工具,然后看到一种思路利用runtime便利属性,可以拿到状态栏中的一个属性:
Ivar *ivars = class_copyIvarList([UIApplication sharedApplication].class, &count);
在for循环打印会拿到一个statusBar属性
id statusBar = [[UIApplication sharedApplication] valueForKeyPath:@"statusBar"];
再次遍历属性,拿到_foregroundView这个属性
Ivar *ivars = class_copyIvarList([statusBar class], &count);
再次遍历这个属性
NSArray *childrenArray = [[[[UIApplication sharedApplication] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
可以得到网络状态的视图UIStatusBarDataNetworkItemView,信号的视图(几格信号)UIStatusBarServiceItemView,电池状态的视图UIStatusBarBatteryItemView,显示时间的视图UIStatusBarTimeItemView
我们需要的就是UIStatusBarDataNetworkItemView,还需要遍历,最终可以拿到dataNetworkType这个属性
Ivar *ivars = class_copyIvarList([NSClassFromString(@"UIStatusBarDataNetworkItemView") class], &count)
id type = [obj valueForKeyPath:@"dataNetworkType"];
这个就是我们需要的最终属性了,其实了解的话也就可以不用rumtime来遍历了,可以直接写,写一个精简版本:
NSArray *children;
if (self.view.bounds.size.height >= 812) {
children = [[[[[UIApplication sharedApplication] valueForKeyPath:@"statusBar"] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
}else {
children = [[[[UIApplication sharedApplication] valueForKeyPath:@"statusBar"] valueForKeyPath:@"foregroundView"] subviews];
}
[children enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
if ([obj isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
NSLog(@"%d", [[obj valueForKeyPath:@"dataNetworkType"] intValue]);
}
}];
注: 打印出的type数字对应的网络状态依次是:0 - 无网络; 1 - 2G; 2 - 3G; 3 - 4G; 5 - WIFI
建议: 将获取的UIStatusBarDataNetworkItemView保存起来,定时去取它的dataNetworkType,这样就可以实时监控网络状态啦(KVO在这里是行不通的哟)
当然,此方法存在一定的局限性,比如当状态栏被隐藏的时候,无法使用此方法。
目前在现在最新的xr,xs,xsMax机型上可能属性有变化获取不到,这种写法可以为大家提供一些思路