iOS tips 3

2015-10-13 | 阅读

UIAlertController的学习

UIAlertController的出现来取代UIAlertViewUIActionSheet,提供了一种模块化替换的方法来代替两者的功能和作用,根据样式设定来决定当前是UIAlertView还是UIActionSheet样式.

UIAlertController继承于UIViewController,创建方法只有以下一种:

+ (instancetype)alertControllerWithTitle:(nullable NSString *)title message:(nullable NSString *)message preferredStyle:(UIAlertControllerStyle)preferredStyle;

初始化时,设置标题和内容,同时设置类型UIAlertControllerStyle,类型有两种,分别为UIAlertControllerStyleActionSheetUIAlertControllerStyleAlert.

主要由两个函数供使用:

- (void)addAction:(UIAlertAction *)action;

UIAlertControllerUIAlertAction来管理按键以及相关响应,其初始化函数为:

+ (instancetype)actionWithTitle:(nullable NSString *)title style:(UIAlertActionStyle)style handler:(void (^ __nullable)(UIAlertAction *action))handler;

可以设定标题,和类型,AlertAction的类型UIAlertActionStyle有三种:

  • UIAlertActionStyleDefault 普通默认按键
  • UIAlertActionStyleCancel 取消按键,不用添加handler,即可点击关闭UIAlertController
  • UIAlertActionStyleDestructive 警告按键,与默认按键相同,主要是颜色是红色的.

handler,为带一个UIAlertAction参数的无返回值的block,在点击时调用.

UIAlertController还有一个常用函数为:

- (void)addTextFieldWithConfigurationHandler:(void (^ __nullable)(UITextField *textField))configurationHandler;

可以在UIAlertControllerStyleAlert模式下,为其内容添加输入框,block为添加输入框后,对其进行的一般性处理操作,如添加KVO或者修饰效果.

最后,显示UIAlertController

[self presentViewController:controller animated:YES completion:nil];

AlertController只能在iOS8及以上使用,且其弹出是基于ViewController的,而不是像UIAlertView一样基于Window的,这就导致当两个AlertView同时弹出是互相覆盖的,而两个AlertController同时弹出时,就只会显示第一个,第二个无法弹出。

IBAction和IBOutlet

两个关键词都是为了通知编译器其与界面对象或者事物相交互.IBAction为 void,而IBOutlet只是一种标记,没有实际意义。

关于performSelector

performSelector的带参数版本:

- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;

当SEL并不接受参数时,事实上performSelector并不会将参数强行传进去.也就是说,对于Target-Action模式,OC总是使用两个参数版本的performSelector并尝试传两个参数进去,而所有的Action只有三种模式,三种模式都可以接受到这个消息,所以都能正确响应.

也就是说结合这两条,可以猜测,对于Target-Action模式的实现.如何向不定参数的SEL action发送合适的消息.当其准备向Action发送消息时,执行的是以下形式的代码:

[target performSelector:action withObject:sender withObject:event];

固定传入两个参数,(id)sender(UIEvent *)envent.而action可以处理该参数的时候,参数才会传入,不接受参数时,参数并不会传入.这是performSelector的特性所决定.

触碰事件的处理流程

发生触碰,先进行事件分发Event Delivery来寻找到第一响应者First Responder,将第一次消息发生给这个第一响应者,而如果响应者没有处理,再将事件 通过消息 传递给响应者链的下一个响应者.

iOS系统检查到触碰事件Touch,会将其打包成一个UIEvent对象,放入当前单例的UIApplication的事件队列中,然后由UIApplication将事件传递给UIWindow来处理.

而在UIWindow对象的处理中,其会使用hitTest:withEvent:方法来寻找此次Touch操作的初始点所在的UIView,即最高层的接受到触碰消息的对象,这个过程称为hit-test view.这个过程,首先UIWindow先对自己的内容视图调用hitTest:withEvent:,而此方法会在UIView的子视图的所有视图上调用pointInside:withEvent:来判断点击事件发生位置是否在这个UIView的视图范围内,以确定用户是否点击了该视图.如果pointInside:withEvent:返回YES,再继续对对该SubView子视图上的所有子视图发送hitTest:withEvent:以检测其是否有子视图可以接收到触碰事件.直到找到最高层的UIView来作为hit-test View.

这里需要注意的,对于UIWindow的内容View,显然是可以响应事件的,所以发送消息hitTest:withEvent:来检测其是否有子视图也能响应消息.而对于子视图,调用的是pointInside:withEvent:来检测是否触碰点发送在UIView内.两个函数做得处理时不同的,一个检测是否继续有子视图,一个判断当前视图是否接收到触碰.

hit-test只是在寻找事件发生最接近的UIView,但这个UIView不一定能处理事件,所以要在响应者链中传递.

详细的响应者链

  1. 响应者链主要是由视图(UIView)构成的;
  2. 一个UIView的下一个响应者是它的控制器UIViewController(如果有的话),然后再转给它的父视图(Super View);
  3. UIViewController的下一个响应者为其管理的视图的父视图;
  4. 单例的UIWindow的内容视图UIView 将指向窗口UIWindow作为它的下一个响应者 .
  5. 单例的应用UIApplication是一个响应者链的终点,它的下一个响应者指向nil,以结束整个循环。

还值得注意的是:

hitTest:withEvent:方法将会忽略隐藏(hidden=YES)的视图,禁止用户操作(userInteractionEnabled=YES)的视图,以及alpha级别小于0.01(alpha<0.01)的视图。如果一个子视图的区域超过父视图的bound区域(父视图的clipsToBounds 属性为NO,这样超过父视图bound区域的子视图内容也会显示),那么正常情况下对子视图在父视图之外区域的触摸操作不会被识别,因为父视图的pointInside:withEvent:方法会返回NO,这样就不会继续向下遍历子视图了。当然,也可以重写pointInside:withEvent:方法来处理这种情况。

使用Charles进行抓包

Charles是MAC下网络抓包工具,

官网处进行下载安装.如果要截取SSL协议相关内容,需要安装Charles的CA证书.下载CA证书,然后双击.crt文件,选择总是信任该证书.

设置代理,在菜单Proxy->Mac OS Proxy来选择是否将Charles设置为系统代理.

Charles提供了2种查看抓包的视图,为StructureSequence。而且会对JSON内容进行格式化,方便查看.

  • Structure 视图将网络请求按访问的域名分类。
  • Sequence 视图将网络请求按访问的时间排序。

过滤网络请求,在sequence界面的中间有Filter输入栏,可以输入关键字来进行请求过滤.也可以专门菜单Porxy->Recording Settings->Include栏中,添加一个项目,来监听目标网站的封包.

Iphone上抓包

在设置中选择Enable transparent HTTP proxying,允许作为HTTP代理. iPhone上的设置:电脑上打开Terminal,输入ifconfig,查看到ip地址,在iphone于PC在同一局域网的情况下,让PC来做iphone得代理,从而可以对iphone进行抓包.而如果是模拟器的话,不用设置就可以抓包.

设置代理,在iPone的设置-无线局域网,选择Wifi详情,可以看到当前连接上的wifi详细信息,对于HTTP代理,选择手动,填上PC的IP,以及端口号8888.然后Charles会弹窗确认,点击允许即可.