Swift学习之二 - 张超耀 深度理解”?” && “!” 1 Optional 其实是个enum ,里面有None 和Some两种类型。 nil就是Optional .None , 非nil就是Optional .Some, 然后会通过Some(T)包装(wrap)原始值,这也是为什么在使用Optional 的时候要拆包(从enum 里取出来原始值)的原因。声明为Optional 只需要在类型后面紧跟一个"?" 即可
1 2 var strValue : String? var strValue1 : Optional<Int>
一旦声明为Optional的,如果不显式的赋值就会有个默认值nil。判断一个Optional的值是否有值,可以用if来判断:
1 2 3 if (strValue != nil) { //do sth with strValue }
怎么使用Optional值呢? 在使用Optional值的时候只前面需要加上一个”?”,就是这么简单。
这个”?”什么意思?: 1、 询问是否响应后面这个方法,如果是nil值,也就是Optional.None,就不响应后面的方法,直接跳过, 2、 如果有值,就是Optional.Some,可能就会拆包(unwrap),然后对拆包后的值执行后面的操作,比如
1 let hash Value = strValue?.hashValue
1 let hash Value1 = strValue!.hashValue
上面错误提示需要拆包(unwrap)后才能得到值,然后才能对其操作,那怎么来拆包呢?拆包提到了几种方法,一种是Optional Binding
1 2 3 if let str = strValue { let hashValue = str.hashValue }
还有一种是在具体的操作前添加”!”符号。
1 let hash Value2 = strValue!.hashValue
这里的”!”表示我确定肯定这里的的strValue一定是非nil的,随便用吧,木事de 就像下面:
1 2 3 if (strValue != nil) { let hash Value = strValue!.hashValue }
1 2 里的strValue一定是非nil 的,所以就能直接加上!,强制拆包(unwrap)并执行后面的操作。 当然如果不加判断,strValue不小心为nil 的话,就会出错,crash掉。
51offer例子解释『隐式拆包的Optional』
1 这种是特殊的Optional ,称为Implicitly Unwrapped Optionals, 直译就是隐式拆包的Optional ,就等于说你每次对这种类型的值操作时,都会自动在操作前补上一个
swift 断言 1 2 3 4 断言(Assertions) Optionals可以让我们检测值是否存在。在某些情况下,如果某个值不存在或者没有提供特定的满足条件,代码不应该继续往下执行。 在这些情况下,可以使用触发断言来终止执行并提供调试。 断言是在运行时检测条件是否为true ,如果为true ,就继续往下执行,否则就在这里中断。
1 2 3 var jobs = "我是一个好人" assert (jobs == "我是一个好人" , "我是一个好人" ) assert (jobs == "我是一个坏人" , "我是一个坏人么?" )
1 2 3 4 5 什么时候使用断言呢? 包含下面的情况时使用断言: 1 、整型下标索引作为值传给自定义索引实现的参数时,但下标索引值不能太低也不能太高时,使用断言 **2 、传值给函数但如果这个传过来的值无效时,函数就不能完成功能时,使用断言。 3 、Optional值当前为nil ,但是后面的代码成功执行的条件是要求这个值不能为nil ,使用断言
IM中输入框的优化方案实现 以下图的输入框为例
输入框的呈现方式选择 以下两个方法对比
Keyboard的inputAccessoryView
相对推荐的方法,有更好的丰富的交互效果
可以与scrollView的一些属性直接绑定
传统的方法
优点:灵活控制显示位置
缺点:过多的计算frame
案例见GitHub的Demo
iOS的输入源都有输入源(keyboard及keyboard的配件InputAccessoryView),那通常的方法是输入源控件(Textfield、TextView等)使用一般的InputView的frame适应
解释几个技巧点
InputView( 输入源 )的父视图作为该InputView的InputAccessoryView,要避免相互引用
巧用第三方不可见的InputView在适当时间点转移第一响应者给可见的InputView
完成编辑时去除第一响应者(注意iOS9下键盘响应逻辑视图层级都发生了变化)
主要代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 + (UUInputAccessoryView *)sharedView { static dispatch_once_t once; static UUInputAccessoryView *sharedView; dispatch_once (&once, ^ { sharedView = [[UUInputAccessoryView alloc] init]; sharedView->btnBack = [UIButton buttonWithType:UIButtonTypeCustom ]; sharedView->btnBack.frame = CGRectMake (0 , 0 , UUIAV_MAIN_W , UUIAV_MAIN_H ); [sharedView->btnBack addTarget:sharedView action:@selector (dismiss) forControlEvents:UIControlEventTouchUpInside ]; sharedView->btnBack.backgroundColor =[UIColor clearColor]; UIToolbar *toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake (0 , 0 , UUIAV_MAIN_W , 44 )]; sharedView->inputView = [[UITextField alloc]initWithFrame:CGRectMake (UUIAV_Edge_Hori , UUIAV_Edge_Vert , UUIAV_MAIN_W -UUIAV_Btn_W -4 *UUIAV_Edge_Hori , UUIAV_Btn_H )]; sharedView->inputView.borderStyle = UITextBorderStyleRoundedRect ; sharedView->inputView.returnKeyType = UIReturnKeyDone ; sharedView->inputView.clearButtonMode = UITextFieldViewModeWhileEditing ; sharedView->inputView.enablesReturnKeyAutomatically = YES ; sharedView->inputView.delegate = sharedView; [toolbar addSubview:sharedView->inputView]; sharedView->assistView = [[UITextField alloc]init]; sharedView->assistView.delegate = sharedView; sharedView->assistView.returnKeyType = UIReturnKeyDone ; sharedView->assistView.enablesReturnKeyAutomatically = YES ; [sharedView->btnBack addSubview:sharedView->assistView]; sharedView->assistView.inputAccessoryView = toolbar; sharedView->BtnSave = [UIButton buttonWithType:UIButtonTypeCustom ]; sharedView->BtnSave.frame = CGRectMake (UUIAV_MAIN_W -UUIAV_Btn_W -2 *UUIAV_Edge_Hori , UUIAV_Edge_Vert , UUIAV_Btn_W , UUIAV_Btn_H ); sharedView->BtnSave.backgroundColor = [UIColor clearColor]; [sharedView->BtnSave setTitle:@"确定" forState:UIControlStateNormal ]; [sharedView->BtnSave setTitleColor:[UIColor redColor] forState:UIControlStateNormal ]; [sharedView->BtnSave addTarget:sharedView action:@selector (Done) forControlEvents:UIControlEventTouchUpInside ]; [toolbar addSubview:sharedView->BtnSave]; }); CGRectGetHeight ([UIScreen mainScreen].bounds ); return sharedView; }
实现逻辑代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 + (void )showKeyboardType:(UIKeyboardType )type content:(NSString *)content Block:(UUInputAccessoryBlock )block { [[UUInputAccessoryView sharedView] show:block keyboardType:type content:content]; } - (void )show:(UUInputAccessoryBlock )block keyboardType:(UIKeyboardType )type content:(NSString *)content { UIWindow *window=[UIApplication sharedApplication].keyWindow ; [window addSubview:btnBack]; inputBlock = block; inputView.text = content; inputView.keyboardType = type; assistView.keyboardType = type; [assistView becomeFirstResponder]; shouldDismiss = NO ; [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) { if (!shouldDismiss) { [inputView becomeFirstResponder]; } }]; } - (void )Done { [inputView resignFirstResponder]; !inputBlock ?: inputBlock(inputView.text ); [self dismiss]; } - (BOOL )textFieldShouldReturn:(UITextField *)textField { [self Done]; return NO ; } - (void )dismiss { shouldDismiss = YES ; [inputView resignFirstResponder]; [btnBack removeFromSuperview]; [[NSNotificationCenter defaultCenter] removeObserver:self ]; }
案例见GitHub的Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @objc func keyboardFrameChanged(notification: NSNotification) { let dict = NSDictionary(dictionary: notification.userInfo!) let keyboardValue = dict.objectForKey(UIKeyboardFrameEndUserInfoKey) as! NSValue let bottomDistance = mainScreenSize() .height - keyboardValue.CGRectValue() .origin.y let duration = Double(dict.objectForKey(UIKeyboardAnimationDurationUserInfoKey) as! NSNumber) UIView.animateWithDuration(duration, animations: { self.inputViewConstraint!.constant = -bottomDistance self.view.layoutIfNeeded() }, completion: { (value: Bool) in self.chatTableView.scrollToBottom(animation: true ) }) }
常见隐藏keyboard的一些方式
TouchBeigin
DidDrag
EndDrag
Interactive
iOS7 开始,ScrollView提供
1 2 3 4 5 6 @available (iOS 7.0 , *)public enum UIScrollViewKeyboardDismissMode : Int { case None case OnDrag case Interactive }
所以在ScrollView上添加scrollView.keyboardDismissMode = UIScrollViewKeyboardDismissMode.Interactive
就可以了。 效果详见iOS7及以上原生设备的短信滑动消失键盘的交互
写负责任的代码之异常处理 - 曾铭
千万不要以为你可以忽视这个特殊的返回值,因为它是一种“可能性”。代码漏掉任何一种可能出现的情况,都可能产生意想不到的灾难性结果。
重视代码(及业务)逻辑的异常情况,将其视为『正常流程』的一部分。
重视函数的抛出异常,将其视为返回值之一(union类型)。
政策之后的对策 1 2 String foo () throws MyException {}
1 2 3 4 5 6 7 try { ... ... ... foo() ... ... ... } catch (Exception e) {}
我们 API 为什么难调试
Service 层未声明抛出异常,也会抛出异常
抛出的异常 API 层记入日志,向上抛时却丢弃了异常信息
API 层方法代码全部 try,很难定位到是哪一行出问题
推荐的对策
只 catch 指定的 exception
try 进可能的小
1 2 3 4 5 try { foo(); } catch (MyException e) { Log.warning(e); }
源头思考全部可能性,内部的问题不抛给别人
不要试图忽略(隐藏)错误,每次出错都是优化代码(反思自己局限)的好机会。否则,你终将付出代价。